/* This is part of ODS2, originally written by Paul Nankervis, * email address: Paulnank@au1.ibm.com * ODS2 is distributed freely for all members of the * VMS community to use. However all derived works * must maintain comments in their source to acknowledge * the contributions of the original author and * subsequent contributors. This is free software; no * warranty is offered, and while we believe it to be useful, * you use it at your own risk. */ #if !defined( DEBUG ) && defined( DEBUG_TERMIO ) #define DEBUG DEBUG_TERMIO #else #ifndef DEBUG #define DEBUG 0 #endif #endif #ifdef _WIN32 #include #else #include #include #endif #include "cmddef.h" extern int interactive; #ifdef USE_LIBEDIT #include #ifdef HAVE_TERMCAP_H #include #elif defined HAVE_TERM_H #include #elif defined HAVE_CURSES_H #include #else int tgetent (char *buffer, char *termtype); char *tgetstr (char *name, char **area); int tgetnum (char *name); int tgetflag (char *name); #endif extern EditLine *editline; /* Max size of a terminal description - documented as ">1024, probably 2048" */ #define TERMENTMAX (4096) #define TERM_CLR_EOL caps[0].val #define TERM_CUR_UP caps[1].val #define TERM_CR caps[2].val static struct cap { char *id; char *val; char *def; } caps[] = { {"ce", NULL,"\r "\ " \r" }, {"up", NULL, ""}, {"cr", NULL, "\r"}, {NULL, NULL, NULL} }; static int have_caps = 0; static void get_termattrs(void) { int ok; struct cap *cp; char *tentbuf, *term; if( have_caps ) { return; } have_caps = 1; tentbuf = (char *)calloc( 1, TERMENTMAX ); /* May be ignored, or have desc. */ if( !tentbuf ) { perror( "calloc" ); exit( EXIT_FAILURE ); } term = getenv( "TERM" ); if( !(term && *term) ) { term = "vt100"; } ok = tgetent(tentbuf, term ); if( ok <= 0 ) { if( ok < 0 ) fprintf( stderr, "Can't access termcap database\n" ); else fprintf( stderr, "Terminal '%s' is not defined in termcap\n", term ); for( cp = caps; cp->id; cp++ ) cp->val = cp->def; } else { char *parbuf; parbuf = calloc( 1, TERMENTMAX ); if( !parbuf ) { perror("calloc"); exit( EXIT_FAILURE ); } for( cp = caps; cp->id; cp++ ) { char *area = parbuf; cp->val = tgetstr( cp->id, &area ); if( cp->val ) { size_t vlen; vlen = strlen( cp->val ) + 1; area = malloc( vlen ); if( !area ) { perror( "malloc"); exit( EXIT_FAILURE ); } memcpy( area, cp->val, vlen ); cp->val = area; } else { fprintf( stderr, "No %s for %s terminal\n", cp->id, term ); cp->val = cp->def; } } free( parbuf ); } free( tentbuf ); } #endif /******************************************************************* confirm_cmd() */ vmscond_t confirm_cmd( vmscond_t status, ... ) { va_list ap; char *response, *mp, *buf = NULL; size_t bufsize = 16; vmscond_t rcode; do { va_start( ap, status ); (void) vprintmsg( status, MSG_TEXT | MSG_WITHARGS | MSG_NOCRLF, ap ); va_end( ap ); fflush( stdout ); mp = response = fgetline( stdin, FALSE, &buf, &bufsize ); while( mp != NULL && (*mp == ' ' || *mp == '\t') ) ++mp; if( mp != NULL && ( *mp == '\0' || keycomp( mp, "NO" ) || keycomp( mp, "FALSE" ) || keycomp( mp, "0" ) ) ) { rcode = ODS2_CONFIRM_NO; break; } if( mp == NULL || keycomp( mp, "ALL" ) ) { rcode = ODS2_CONFIRM_ALL; break; } if( keycomp( mp, "YES" ) || keycomp( mp, "TRUE" ) || keycomp( mp, "1" ) ) { rcode = ODS2_CONFIRM_YES; break; } if( keycomp( mp, "QUIT" ) ) { rcode = ODS2_CONFIRM_QUIT; break; } putchar( '\b' ); } while( 1 ); if( buf != NULL ) free( buf ); return rcode | STS$M_INHIB_MSG; } /******************************************************************* put_str() */ vmscond_t put_str( const char *buf, FILE *outf, pause_t *pause ) { return put_strn( buf, strlen( buf ), outf, pause ); } /******************************************************************* put_str() */ vmscond_t put_strn( const char *buf, size_t len, FILE *outf, pause_t *pause ) { vmscond_t sts; if( len == 0 ) return SS$_NORMAL; if( pause == NULL || pause->interval == 0 ) { fwrite( buf, len, 1, outf ); return SS$_NORMAL; } while( len-- ) if( $FAILS(sts = put_c( *buf++, outf, pause )) ) return sts; return SS$_NORMAL; } /******************************************************************* put_c() */ vmscond_t put_c( int c, FILE *outf, pause_t *pause ) { vmscond_t sts; fputc( c, outf ); if( c != '\n' || pause == NULL || pause->interval == 0 ) { return SS$_NORMAL; } sts = SS$_NORMAL; if( ++pause->lineno < pause->interval ) return SS$_NORMAL; printmsg( pause->prompt, MSG_TEXT | MSG_NOCRLF ); fflush( stdout ); #ifdef USE_LIBEDIT if( interactive ) { get_termattrs(); while( 1 ) { char ch; c = el_getc( editline, &ch ); if( c > 0 ) { putchar( ch ); fflush( stdout ); if( ch == '\r' ) continue; } if( c == 0 ) { ch = '\n'; sts = SS$_ABORT; } else if( tolower( ch ) == 'q' ) { sts = SS$_ABORT; continue; } else if( tolower( ch ) == 'f' ) { pause->interval = 0; continue; } if( ch == '\n' ) { pause->lineno = 0; printf( "%s%s%s", TERM_CR, TERM_CUR_UP, TERM_CLR_EOL ); fflush( stdout ); return sts | STS$M_INHIB_MSG; } el_beep(editline); } } else #endif { while( 1 ) { c = getchar(); if( c == '\r' ) { continue; } if( c == EOF ) { c = '\n'; sts = SS$_ABORT; } else if( tolower( c ) == 'q' ) { sts = SS$_ABORT; continue; } else if( tolower( c ) == 'f' ) { pause->interval = 0; continue; } if( c == '\n' ) { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; size_t wid; fflush( stdout ); GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi ); wid = (size_t)csbi.srWindow.Right - csbi.srWindow.Left + 1; --csbi.dwCursorPosition.Y; csbi.dwCursorPosition.X = 0; SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), csbi.dwCursorPosition ); while( wid-- ) putchar( ' ' ); SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), csbi.dwCursorPosition ); #else putchar( '\r' ); #endif pause->lineno = 0; fflush( stdout ); return sts | STS$M_INHIB_MSG; } putchar( '\b' ); } } } /******************************************************************* termchar() */ void termchar( int *width, int *height ) { if( width != NULL ) *width = 80; if( height != NULL ) *height = 24; { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); if( width != NULL ) *width = csbi.srWindow.Right - csbi.srWindow.Left + 1; if( height != NULL ) *height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #else #ifdef TIOCGSIZE struct ttysize ts; ioctl(STDIN_FILENO, TIOCGSIZE, &ts); if( width != NULL ) *width = ts.ts_cols; if( height != NULL ) *height = ts.ts_lines; #elif defined(TIOCGWINSZ) struct winsize ts; ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); if( width != NULL ) *width = ts.ws_col; if( height != NULL ) *height = ts.ws_row; #endif /* TIOCGSIZE */ #endif } return; }