diff options
Diffstat (limited to 'main_loop.c')
-rw-r--r-- | main_loop.c | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/main_loop.c b/main_loop.c new file mode 100644 index 0000000..24603b7 --- /dev/null +++ b/main_loop.c @@ -0,0 +1,730 @@ +/* GNU ed - The GNU line editor. + Copyright (C) 1993, 1994 Andrew Moore, Talke Studio + Copyright (C) 2006, 2007, 2008, 2009 Antonio Diaz Diaz. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <ctype.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ed.h" + + +enum Status { ERR = -2, EMOD = -3, FATAL = -4 }; + +static char def_filename[1024] = ""; /* default filename */ +static char errmsg[80] = ""; /* error message buffer */ +static char prompt_str[80] = "*"; /* command-line prompt */ +static const char *ibufp = 0; /* pointer to ed command-line buffer */ +static char *shcmd = 0; /* shell command buffer */ +static int shcmdsz = 0; /* shell command buffer size */ +static int shcmdlen = 0; /* shell command length */ +static int first_addr = 0, second_addr = 0; +static char verbose = 0; /* if set, print all error messages */ +static char prompt_on = 0; /* if set, show command-line prompt */ + + +void set_def_filename( const char *s ) + { + strncpy( def_filename, s, sizeof( def_filename ) ); + def_filename[sizeof(def_filename)-1] = 0; + } + +void set_prompt( const char *s ) + { + prompt_on = 1; + strncpy( prompt_str, s, sizeof( prompt_str ) ); + prompt_str[sizeof(prompt_str)-1] = 0; + } + +void set_verbose( void ) { verbose = 1; } + + +static const line_t *mark[26]; /* line markers */ +static int markno; /* line marker count */ + +static char mark_line_node( const line_t *lp, int c ) + { + c -= 'a'; + if( c < 0 || c >= 26 ) { set_error_msg( "Invalid mark character" ); return 0; } + if( !mark[c] ) ++markno; + mark[c] = lp; + return 1; + } + + +void unmark_line_node( const line_t *lp ) + { + int i; + for( i = 0; markno && i < 26; ++i ) + if( mark[i] == lp ) + { mark[i] = 0; --markno; } + } + + +/* return address of a marked line */ +static int get_marked_node_addr( int c ) + { + c -= 'a'; + if( c < 0 || c >= 26 ) + { set_error_msg( "Invalid mark character" ); return -1; } + return get_line_node_addr( mark[c]); + } + + +/* read a shell command from stdin; return substitution status ( -1, 0, +1 ) */ +static int get_shell_command( void ) + { + static char *buf = 0; + static int bufsz = 0; + const char *s; /* substitution char pointer */ + int i = 0, len; + + if( restricted() ) { set_error_msg( "Shell access restricted" ); return -1; } + s = ibufp = get_extended_line( ibufp, &len, 1 ); + if( !s ) return -1; + if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return -1; + buf[i++] = '!'; /* prefix command w/ bang */ + while( *ibufp != '\n' ) + { + if( *ibufp == '!' ) + { + if( s != ibufp ) + { + if( !resize_buffer( &buf, &bufsz, i + 1 ) ) return -1; + buf[i++] = *ibufp++; + } + else if( !shcmd || ( traditional() && !*( shcmd + 1 ) ) ) + { set_error_msg( "No previous command" ); return -1; } + else + { + if( !resize_buffer( &buf, &bufsz, i + shcmdlen ) ) return -1; + for( s = shcmd + 1; s < shcmd + shcmdlen; ) buf[i++] = *s++; + s = ibufp++; + } + } + else if( *ibufp == '%' ) + { + if( !def_filename[0] ) + { set_error_msg( "No current filename" ); return -1; } + len = strlen( s = strip_escapes( def_filename ) ); + if( !resize_buffer( &buf, &bufsz, i + len ) ) return -1; + while( len-- ) buf[i++] = *s++; + s = ibufp++; + } + else + { + if( !resize_buffer( &buf, &bufsz, i + 2 ) ) return -1; + buf[i++] = *ibufp; + if( *ibufp++ == '\\' ) buf[i++] = *ibufp++; + } + } + if( !resize_buffer( &shcmd, &shcmdsz, i + 1 ) ) return -1; + memcpy( shcmd, buf, i ); + shcmdlen = i; shcmd[i] = 0; + return ( *s == '!' || *s == '%' ); + } + + +static const char *skip_blanks( const char *s ) + { + while( isspace( (unsigned char)*s ) && *s != '\n' ) ++s; + return s; + } + + +/* return pointer to copy of filename in the command buffer */ +static const char *get_filename( void ) + { + static char *buf = 0; + static int bufsz = 0; + int size, n; + + ibufp = skip_blanks( ibufp ); + if( *ibufp != '\n' ) + { + ibufp = get_extended_line( ibufp, &size, 1 ); + if( !ibufp ) return 0; + if( *ibufp == '!' ) + { + ++ibufp; + n = get_shell_command(); + if( n < 0 ) return 0; + if( n ) printf( "%s\n", shcmd + 1 ); + return shcmd; + } + else if( size > path_max( 0 ) ) + { set_error_msg( "Filename too long" ); return 0; } + } + else if( !traditional() && !def_filename[0] ) + { set_error_msg( "No current filename" ); return 0; } + if( !resize_buffer( &buf, &bufsz, path_max( 0 ) + 1 ) ) return 0; + for( n = 0; *ibufp != '\n'; ) buf[n++] = *ibufp++; + buf[n] = 0; + return ( may_access_filename( buf ) ? buf : 0 ); + } + + +static void invalid_address( void ) { set_error_msg( "Invalid address" ); } + + +/* return the next line address in the command buffer */ +static int next_addr( int *addr_cnt ) + { + const char *hd = ibufp = skip_blanks( ibufp ); + int addr = current_addr(); + int first = 1; + + while( 1 ) + { + int n; + const unsigned char ch = *ibufp; + if( isdigit( ch ) ) + { + if( !first ) { invalid_address(); return -2; }; + if( !parse_int( &addr, ibufp, &ibufp ) ) return -2; + } + else switch( ch ) + { + case '+': + case '\t': + case ' ': + case '-': ibufp = skip_blanks( ++ibufp ); + if( isdigit( (unsigned char)*ibufp ) ) + { + if( !parse_int( &n, ibufp, &ibufp ) ) return -2; + addr += ( ( ch == '-' ) ? -n : n ); + } + else if( ch == '+' ) ++addr; + else if( ch == '-' ) --addr; + break; + case '.': + case '$': if( !first ) { invalid_address(); return -2; }; + ++ibufp; addr = ( ( ch == '.' ) ? current_addr() : last_addr() ); + break; + case '/': + case '?': if( !first ) { invalid_address(); return -2; }; + addr = get_matching_node_addr( &ibufp, ch == '/' ); + if( addr < 0 ) return -2; + if( ch == *ibufp ) ++ibufp; + break; + case '\'':if( !first ) { invalid_address(); return -2; }; + ++ibufp; addr = get_marked_node_addr( *ibufp++ ); + if( addr < 0 ) return -2; + break; + case '%': + case ',': + case ';': if( first ) + { + ++ibufp; ++*addr_cnt; + second_addr = ( ( ch == ';' ) ? current_addr() : 1 ); + addr = last_addr(); + break; + } /* FALL THROUGH */ + default: if( ibufp == hd ) return -1; /* EOF */ + if( addr < 0 || addr > last_addr() ) + { invalid_address(); return -2; } + ++*addr_cnt; return addr; + } + first = 0; + } + } + + +/* get line addresses from the command buffer until an invalid address + is seen. Return number of addresses read */ +static int extract_addr_range( void ) + { + int addr; + int addr_cnt = 0; + + first_addr = second_addr = current_addr(); + while( ( addr = next_addr( &addr_cnt ) ) >= 0 ) + { + first_addr = second_addr; second_addr = addr; + if( *ibufp != ',' && *ibufp != ';' ) break; + if( *ibufp++ == ';' ) set_current_addr( addr ); + } + if( addr_cnt == 1 || second_addr != addr ) first_addr = second_addr; + return ( ( addr != -2 ) ? addr_cnt : -1 ); + } + + +/* get a valid address from the command buffer */ +static char get_third_addr( int *addr ) + { + int ol1 = first_addr; + int ol2 = second_addr; + + int addr_cnt = extract_addr_range(); if( addr_cnt < 0 ) return 0; + if( traditional() && addr_cnt == 0 ) + { set_error_msg( "Destination expected" ); return 0; } + if( second_addr < 0 || second_addr > last_addr() ) + { invalid_address(); return 0; } + *addr = second_addr; + first_addr = ol1; second_addr = ol2; + return 1; + } + + +/* return true if address range is valid */ +static char check_addr_range( const int n, const int m, const int addr_cnt ) + { + if( addr_cnt == 0 ) + { + first_addr = ( ( n >= 0 ) ? n : current_addr() ); + second_addr = ( ( m >= 0 ) ? m : current_addr() ); + } + if( first_addr < 1 || first_addr > second_addr || second_addr > last_addr() ) + { invalid_address(); return 0; } + return 1; + } + + +/* verify the command suffix in the command buffer */ +static char get_command_suffix( int *gflagsp ) + { + while( 1 ) + { + const char ch = *ibufp; + if( ch == 'l' ) *gflagsp |= GLS; + else if( ch == 'n' ) *gflagsp |= GNP; + else if( ch == 'p' ) *gflagsp |= GPR; + else break; + ++ibufp; + } + if( *ibufp++ != '\n' ) + { set_error_msg( "Invalid command suffix" ); return 0; } + return 1; + } + + +static char unexpected_address( const int addr_cnt ) + { + if( addr_cnt > 0 ) { set_error_msg( "Unexpected address" ); return 1; } + return 0; + } + +static char unexpected_command_suffix( const unsigned char ch ) + { + if( !isspace( ch ) ) + { set_error_msg( "Unexpected command suffix" ); return 1; } + return 0; + } + + +static char command_s( int *gflagsp, const int addr_cnt, const char isglobal ) + { + static int gflags = 0; + static int snum = 0; + enum Sflags { + SGG = 0x01, /* complement previous global substitute suffix */ + SGP = 0x02, /* complement previous print suffix */ + SGR = 0x04, /* use last regex instead of last pat */ + SGF = 0x08 /* repeat last substitution */ + } sflags = 0; + + do { + if( isdigit( (unsigned char)*ibufp ) ) + { + if( !parse_int( &snum, ibufp, &ibufp ) ) return 0; + sflags |= SGF; gflags &= ~GSG; /* override GSG */ + } + else switch( *ibufp ) + { + case '\n':sflags |= SGF; break; + case 'g': sflags |= SGG; ++ibufp; break; + case 'p': sflags |= SGP; ++ibufp; break; + case 'r': sflags |= SGR; ++ibufp; break; + default: if( sflags ) + { set_error_msg( "Invalid command suffix" ); return 0; } + } + } + while( sflags && *ibufp != '\n' ); + if( sflags && !prev_pattern() ) + { set_error_msg( "No previous substitution" ); return 0; } + if( sflags & SGG ) snum = 0; /* override numeric arg */ + if( *ibufp != '\n' && ibufp[1] == '\n' ) + { set_error_msg( "Invalid pattern delimiter" ); return 0; } + if( ( !sflags || ( sflags & SGR ) ) && !new_compiled_pattern( &ibufp ) ) + return 0; + if( !sflags && !extract_subst_tail( &ibufp, &gflags, &snum, isglobal ) ) + return 0; + if( isglobal ) gflags |= GLB; + else gflags &= ~GLB; + if( sflags & SGG ) gflags ^= GSG; + if( sflags & SGP ) { gflags ^= GPR; gflags &= ~( GLS | GNP ); } + switch( *ibufp ) + { + case 'l': gflags |= GLS; ++ibufp; break; + case 'n': gflags |= GNP; ++ibufp; break; + case 'p': gflags |= GPR; ++ibufp; break; + } + if( !check_addr_range( -1, -1, addr_cnt ) ) return 0; + if( !get_command_suffix( gflagsp ) ) return 0; + if( !isglobal ) clear_undo_stack(); + if( !search_and_replace( first_addr, second_addr, gflags, snum, isglobal ) ) + return 0; + if( ( gflags & ( GPR | GLS | GNP ) ) && + !display_lines( current_addr(), current_addr(), gflags ) ) + return 0; + return 1; + } + + +static char exec_global( const char *ibufp2, int gflags, const char interact ); +/* execute the next command in command buffer; return error status */ +static int exec_command( const char isglobal ) + { + const char *fnp; + int gflags = 0; + int addr, c, n; + + const int addr_cnt = extract_addr_range(); if( addr_cnt < 0 ) return ERR; + ibufp = skip_blanks( ibufp ); + c = *ibufp++; + switch( c ) + { + case 'a': if( !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !append_lines( ibufp, second_addr, isglobal ) ) return ERR; + ibufp = ""; + break; + case 'c': if( first_addr == 0 ) first_addr = 1; + if( second_addr == 0 ) second_addr = 1; + if( !check_addr_range( -1, -1, addr_cnt ) || + !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !delete_lines( first_addr, second_addr, isglobal ) || + !append_lines( ibufp, current_addr(), isglobal ) ) return ERR; + ibufp = ""; + break; + case 'd': if( !check_addr_range( -1, -1, addr_cnt ) || + !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !delete_lines( first_addr, second_addr, isglobal ) ) return ERR; + inc_current_addr(); + break; + case 'e': if( modified() && !scripted() ) return EMOD; /* fall through */ + case 'E': if( unexpected_address( addr_cnt ) || + unexpected_command_suffix( *ibufp ) ) return ERR; + fnp = get_filename(); + if( !fnp || !get_command_suffix( &gflags ) || + !delete_lines( 1, last_addr(), isglobal ) ) return ERR; + if( !close_sbuf() ) return ERR; + if( !open_sbuf() ) return FATAL; + if( fnp[0] && fnp[0] != '!' ) set_def_filename( fnp ); + if( traditional() && !fnp[0] && !def_filename[0] ) + { set_error_msg( "No current filename" ); return ERR; } + if( read_file( fnp[0] ? fnp : def_filename, 0 ) < 0 ) + return ERR; + reset_undo_state(); set_modified( 0 ); + break; + case 'f': if( unexpected_address( addr_cnt ) || + unexpected_command_suffix( *ibufp ) ) return ERR; + fnp = get_filename(); + if( !fnp ) return ERR; + if( fnp[0] == '!' ) + { set_error_msg( "Invalid redirection" ); return ERR; } + if( !get_command_suffix( &gflags ) ) return ERR; + if( fnp[0] ) set_def_filename( fnp ); + printf( "%s\n", strip_escapes( def_filename ) ); + break; + case 'g': + case 'v': + case 'G': + case 'V': if( isglobal ) + { set_error_msg( "Cannot nest global commands" ); return ERR; } + n = ( c == 'g' || c == 'G' ); /* mark matching lines */ + if( !check_addr_range( 1, last_addr(), addr_cnt ) || + !build_active_list( &ibufp, first_addr, second_addr, n ) ) + return ERR; + n = ( c == 'G' || c == 'V' ); /* interact */ + if( ( n && !get_command_suffix( &gflags ) ) || + !exec_global( ibufp, gflags, n ) ) + return ERR; + break; + case 'h': + case 'H': if( unexpected_address( addr_cnt ) || + !get_command_suffix( &gflags ) ) return ERR; + if( c == 'H' ) verbose = !verbose; + if( ( c == 'h' || verbose ) && errmsg[0] ) + fprintf( stderr, "%s\n", errmsg ); + break; + case 'i': if( second_addr == 0 ) second_addr = 1; + if( !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !append_lines( ibufp, second_addr - 1, isglobal ) ) return ERR; + ibufp = ""; + break; + case 'j': if( !check_addr_range( -1, current_addr() + 1, addr_cnt ) || + !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( first_addr != second_addr && + !join_lines( first_addr, second_addr, isglobal ) ) return ERR; + break; + case 'k': n = *ibufp++; + if( second_addr == 0 ) { invalid_address(); return ERR; } + if( !get_command_suffix( &gflags ) || + !mark_line_node( search_line_node( second_addr ), n ) ) + return ERR; + break; + case 'l': + case 'n': + case 'p': if( c == 'l' ) n = GLS; else if( c == 'n' ) n = GNP; else n = GPR; + if( !check_addr_range( -1, -1, addr_cnt ) || + !get_command_suffix( &gflags ) || + !display_lines( first_addr, second_addr, gflags | n ) ) + return ERR; + gflags = 0; + break; + case 'm': if( !check_addr_range( -1, -1, addr_cnt ) || + !get_third_addr( &addr ) ) return ERR; + if( addr >= first_addr && addr < second_addr ) + { set_error_msg( "Invalid destination" ); return ERR; } + if( !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !move_lines( first_addr, second_addr, addr, isglobal ) ) + return ERR; + break; + case 'P': + case 'q': + case 'Q': if( unexpected_address( addr_cnt ) || + !get_command_suffix( &gflags ) ) return ERR; + if( c == 'P' ) prompt_on = !prompt_on; + else return ( ( modified() && !scripted() && c == 'q' ) ? EMOD : -1 ); + break; + case 'r': if( unexpected_command_suffix( *ibufp ) ) return ERR; + if( addr_cnt == 0 ) second_addr = last_addr(); + fnp = get_filename(); + if( !fnp || !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp ); + if( traditional() && !fnp[0] && !def_filename[0] ) + { set_error_msg( "No current filename" ); return ERR; } + addr = read_file( fnp[0] ? fnp : def_filename, second_addr ); + if( addr < 0 ) return ERR; + if( addr && addr != last_addr() ) set_modified( 1 ); + break; + case 's': if( !command_s( &gflags, addr_cnt, isglobal ) ) return ERR; + break; + case 't': if( !check_addr_range( -1, -1, addr_cnt ) || + !get_third_addr( &addr ) || + !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !copy_lines( first_addr, second_addr, addr ) ) return ERR; + break; + case 'u': if( unexpected_address( addr_cnt ) || + !get_command_suffix( &gflags ) || + !undo( isglobal ) ) return ERR; + break; + case 'w': + case 'W': n = *ibufp; + if( n == 'q' || n == 'Q' ) ++ibufp; + if( unexpected_command_suffix( *ibufp ) ) return ERR; + fnp = get_filename(); + if( !fnp ) return ERR; + if( addr_cnt == 0 && !last_addr() ) first_addr = second_addr = 0; + else if( !check_addr_range( 1, last_addr(), addr_cnt ) ) return ERR; + if( !get_command_suffix( &gflags ) ) return ERR; + if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp ); + if( traditional() && !fnp[0] && !def_filename[0] ) + { set_error_msg( "No current filename" ); return ERR; } + addr = write_file( fnp[0] ? fnp : def_filename, + ( c == 'W' ) ? "a" : "w", first_addr, second_addr ); + if( addr < 0 ) return ERR; + if( addr == last_addr() ) set_modified( 0 ); + else if( modified() && !scripted() && n == 'q' ) return EMOD; + if( n == 'q' || n == 'Q' ) return -1; + break; + case 'x': if( second_addr < 0 || last_addr() < second_addr ) + { invalid_address(); return ERR; } + if( !get_command_suffix( &gflags ) ) return ERR; + if( !isglobal ) clear_undo_stack(); + if( !put_lines( second_addr ) ) return ERR; + break; + case 'y': if( !check_addr_range( -1, -1, addr_cnt ) || + !get_command_suffix( &gflags ) || + !yank_lines( first_addr, second_addr ) ) return ERR; + break; + case 'z': first_addr = 1; + if( !check_addr_range( first_addr, current_addr() + + ( traditional() || !isglobal ), addr_cnt ) ) + return ERR; + if( *ibufp > '0' && *ibufp <= '9' ) + { if( parse_int( &n, ibufp, &ibufp ) ) set_window_lines( n ); + else return ERR; } + if( !get_command_suffix( &gflags ) || + !display_lines( second_addr, min( last_addr(), second_addr + window_lines() ), + gflags ) ) + return ERR; + gflags = 0; + break; + case '=': if( !get_command_suffix( &gflags ) ) return ERR; + printf( "%d\n", addr_cnt ? second_addr : last_addr() ); + break; + case '!': if( unexpected_address( addr_cnt ) ) return ERR; + n = get_shell_command(); + if( n < 0 || !get_command_suffix( &gflags ) ) return ERR; + if( n ) printf( "%s\n", shcmd + 1 ); + system( shcmd + 1 ); + if( !scripted() ) printf( "!\n" ); + break; + case '\n': first_addr = 1; + if( !check_addr_range( first_addr, current_addr() + + ( traditional() || !isglobal ), addr_cnt ) || + !display_lines( second_addr, second_addr, 0 ) ) + return ERR; + break; + case '#': while( *ibufp++ != '\n' ) ; + break; + default: set_error_msg( "Unknown command" ); return ERR; + } + if( gflags && !display_lines( current_addr(), current_addr(), gflags ) ) + return ERR; + return 0; + } + + +/* apply command list in the command buffer to the active lines in a + range; return false if error */ +static char exec_global( const char *ibufp2, int gflags, const char interact ) + { + static char *buf = 0; + static int bufsz = 0; + const line_t *lp = 0; + const char *cmd = 0; + + if( !interact ) + { + if( traditional() && !strcmp( ibufp2, "\n" ) ) + cmd = "p\n"; /* null cmd-list == `p' */ + else if( !( cmd = get_extended_line( ibufp2, 0, 0 ) ) ) + return 0; + } + clear_undo_stack(); + while( ( lp = next_active_node() ) ) + { + set_current_addr( get_line_node_addr( lp ) ); + if( current_addr() < 0 ) return 0; + if( interact ) + { + /* print current_addr; get a command in global syntax */ + int len; + if( !display_lines( current_addr(), current_addr(), gflags ) ) + return 0; + do { ibufp2 = get_tty_line( &len ); } + while( ibufp2 && len > 0 && ibufp2[len-1] != '\n' ); + if( !ibufp2 ) return 0; + if( len == 0 ) { set_error_msg( "Unexpected end-of-file" ); return 0; } + if( len == 1 && !strcmp( ibufp2, "\n" ) ) continue; + if( len == 2 && !strcmp( ibufp2, "&\n" ) ) + { if( !cmd ) { set_error_msg( "No previous command" ); return 0; } } + else if( !( cmd = get_extended_line( ibufp2, &len, 0 ) ) ) return 0; + else + { + if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return 0; + memcpy( buf, cmd, len + 1 ); + cmd = buf; + } + } + ibufp = cmd; + while( *ibufp ) if( exec_command( 1 ) < 0 ) return 0; + } + return 1; + } + + +int main_loop( const char loose ) + { + extern jmp_buf jmp_state; + volatile int err_status = 0; /* program exit status */ + volatile int linenum = 0; /* script line number */ + int len, status, old_status; + + disable_interrupts(); + set_signals(); + status = setjmp( jmp_state ); + if( !status ) enable_interrupts(); + else { status = -1; fputs( "\n?\n", stderr ); set_error_msg( "Interrupt" ); } + + while( 1 ) + { + if( status < 0 && verbose ) fprintf( stderr, "%s\n", errmsg ); + if( prompt_on ) { printf( "%s", prompt_str ); fflush( stdout ); } + ibufp = get_tty_line( &len ); + if( !ibufp ) return err_status; + if( !len ) + { + if( !modified() || scripted() ) return err_status; + fputs( "?\n", stderr ); set_error_msg( "Warning: file modified" ); + if( is_regular_file( 0 ) ) + { + if( verbose ) fprintf( stderr, "script, line %d: %s\n", linenum, errmsg ); + return 2; + } + set_modified( 0 ); status = EMOD; continue; + } + else if( ibufp[len-1] != '\n' ) /* discard line */ + { set_error_msg( "Unexpected end-of-file" ); status = ERR; continue; } + else ++linenum; + old_status = status; + status = exec_command( 0 ); + if( status == 0 ) continue; + if( status == -1 ) return err_status; + if( status == EMOD ) + { + if( old_status == EMOD ) return err_status; + fputs( "?\n", stderr ); /* give warning */ + set_error_msg( "Warning: file modified" ); + if( is_regular_file( 0 ) ) + { + if( verbose ) fprintf( stderr, "script, line %d: %s\n", linenum, errmsg ); + return 1; + } + } + else if( status == FATAL ) + { + if( verbose ) + { + if( is_regular_file( 0 ) ) + fprintf( stderr, "script, line %d: %s\n", linenum, errmsg ); + else fprintf( stderr, "%s\n", errmsg ); + } + return 1; + } + else + { + fputs( "?\n", stderr ); /* give warning */ + if( is_regular_file( 0 ) ) + { + if( verbose ) fprintf( stderr, "script, line %d: %s\n", linenum, errmsg ); + return 1; + } + } + if( !loose ) err_status = 1; + } + } + + +void set_error_msg( const char *msg ) + { + if( !msg ) msg = ""; + strncpy( errmsg, msg, sizeof( errmsg ) ); + errmsg[sizeof(errmsg)-1] = 0; + } |