1 /* GNU ed - The GNU line editor.
2 Copyright (C) 1993, 1994 Andrew Moore, Talke Studio
3 Copyright (C) 2006-2015 Antonio Diaz Diaz.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 enum Status { QUIT = -1, ERR = -2, EMOD = -3, FATAL = -4 };
30 static char def_filename[1024] = ""; /* default filename */
31 static char errmsg[80] = ""; /* error message buffer */
32 static char prompt_str[80] = "*"; /* command prompt */
33 static int first_addr = 0, second_addr = 0;
34 static bool prompt_on = false; /* if set, show command prompt */
35 static bool verbose = false; /* if set, print all error messages */
38 void set_def_filename( const char * const s )
40 strncpy( def_filename, s, sizeof def_filename );
41 def_filename[sizeof(def_filename)-1] = 0;
44 void set_error_msg( const char * msg )
47 strncpy( errmsg, msg, sizeof errmsg );
48 errmsg[sizeof(errmsg)-1] = 0;
51 void set_prompt( const char * const s )
54 strncpy( prompt_str, s, sizeof prompt_str );
55 prompt_str[sizeof(prompt_str)-1] = 0;
58 void set_verbose( void ) { verbose = true; }
61 static const line_t * mark[26]; /* line markers */
62 static int markno; /* line marker count */
64 static bool mark_line_node( const line_t * const lp, int c )
67 if( c < 0 || c >= 26 )
68 { set_error_msg( "Invalid mark character" ); return false; }
69 if( !mark[c] ) ++markno;
75 void unmark_line_node( const line_t * const lp )
78 for( i = 0; markno && i < 26; ++i )
80 { mark[i] = 0; --markno; }
84 /* return address of a marked line */
85 static int get_marked_node_addr( int c )
88 if( c < 0 || c >= 26 )
89 { set_error_msg( "Invalid mark character" ); return -1; }
90 return get_line_node_addr( mark[c]);
94 /* Returns pointer to copy of shell command in the command buffer */
95 static const char * get_shell_command( const char ** const ibufpp )
97 static char * buf = 0;
99 static char * shcmd = 0; /* shell command buffer */
100 static int shcmdsz = 0; /* shell command buffer size */
101 static int shcmdlen = 0; /* shell command length */
102 const char * p; /* substitution char pointer */
105 if( restricted() ) { set_error_msg( "Shell access restricted" ); return 0; }
106 if( !get_extended_line( ibufpp, &len, true ) ) return 0;
108 if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return 0;
109 buf[i++] = '!'; /* prefix command w/ bang */
110 while( **ibufpp != '\n' )
112 if( **ibufpp == '!' )
116 if( !resize_buffer( &buf, &bufsz, i + 1 ) ) return 0;
117 buf[i++] = *(*ibufpp)++;
119 else if( !shcmd || ( traditional() && !*( shcmd + 1 ) ) )
120 { set_error_msg( "No previous command" ); return 0; }
123 if( !resize_buffer( &buf, &bufsz, i + shcmdlen ) ) return 0;
124 for( p = shcmd + 1; p < shcmd + shcmdlen; ) buf[i++] = *p++;
128 else if( **ibufpp == '%' )
130 if( !def_filename[0] )
131 { set_error_msg( "No current filename" ); return 0; }
132 p = strip_escapes( def_filename );
134 if( !resize_buffer( &buf, &bufsz, i + len ) ) return 0;
135 while( len-- ) buf[i++] = *p++;
140 if( !resize_buffer( &buf, &bufsz, i + 2 ) ) return 0;
142 if( *(*ibufpp)++ == '\\' ) buf[i++] = *(*ibufpp)++;
145 while( **ibufpp == '\n' ) ++*ibufpp; /* skip newline */
146 if( !resize_buffer( &shcmd, &shcmdsz, i + 1 ) ) return 0;
147 memcpy( shcmd, buf, i );
148 shcmdlen = i; shcmd[i] = 0;
149 if( *p == '!' || *p == '%' ) printf( "%s\n", shcmd + 1 );
154 static const char * skip_blanks( const char * p )
156 while( isspace( (unsigned char)*p ) && *p != '\n' ) ++p;
161 /* Returns pointer to copy of filename in the command buffer */
162 static const char * get_filename( const char ** const ibufpp )
164 static char * buf = 0;
165 static int bufsz = 0;
166 const int pmax = path_max( 0 );
169 *ibufpp = skip_blanks( *ibufpp );
170 if( **ibufpp != '\n' )
173 if( !get_extended_line( ibufpp, &size, true ) ) return 0;
174 if( **ibufpp == '!' )
177 return get_shell_command( ibufpp );
179 else if( size > pmax )
180 { set_error_msg( "Filename too long" ); return 0; }
182 else if( !traditional() && !def_filename[0] )
183 { set_error_msg( "No current filename" ); return 0; }
184 if( !resize_buffer( &buf, &bufsz, pmax + 1 ) ) return 0;
185 for( n = 0; **ibufpp != '\n'; ++n, ++*ibufpp ) buf[n] = **ibufpp;
187 while( **ibufpp == '\n' ) ++*ibufpp; /* skip newline */
188 return ( may_access_filename( buf ) ? buf : 0 );
192 static void invalid_address( void ) { set_error_msg( "Invalid address" ); }
195 /* return the next line address in the command buffer */
196 static int next_addr( const char ** const ibufpp, int * const addr_cnt )
198 const char * const s = *ibufpp = skip_blanks( *ibufpp );
199 int addr = current_addr();
200 bool first = true; /* true == addr, false == offset */
205 const unsigned char ch = **ibufpp;
208 if( !first ) { invalid_address(); return -2; };
209 if( !parse_int( &addr, *ibufpp, ibufpp ) ) return -2;
216 case '-': *ibufpp = skip_blanks( ++*ibufpp );
217 if( isdigit( (unsigned char)**ibufpp ) )
219 if( !parse_int( &n, *ibufpp, ibufpp ) ) return -2;
220 addr += ( ( ch == '-' ) ? -n : n );
222 else if( ch == '+' ) ++addr;
223 else if( ch == '-' ) --addr;
226 case '$': if( !first ) { invalid_address(); return -2; };
228 addr = ( ( ch == '.' ) ? current_addr() : last_addr() );
231 case '?': if( !first ) { invalid_address(); return -2; };
232 addr = next_matching_node_addr( ibufpp, ch == '/' );
233 if( addr < 0 ) return -2;
234 if( ch == **ibufpp ) ++*ibufpp;
236 case '\'':if( !first ) { invalid_address(); return -2; };
238 addr = get_marked_node_addr( *(*ibufpp)++ );
239 if( addr < 0 ) return -2;
243 case ';': if( first )
245 ++*ibufpp; ++*addr_cnt;
246 second_addr = ( ( ch == ';' ) ? current_addr() : 1 );
250 default : if( *ibufpp == s ) return -1; /* EOF */
251 if( addr < 0 || addr > last_addr() )
252 { invalid_address(); return -2; }
253 ++*addr_cnt; return addr;
260 /* get line addresses from the command buffer until an invalid address
261 is seen. Returns the number of addresses read */
262 static int extract_addr_range( const char ** const ibufpp )
267 first_addr = second_addr = current_addr();
270 addr = next_addr( ibufpp, &addr_cnt );
271 if( addr < 0 ) break;
272 first_addr = second_addr; second_addr = addr;
273 if( **ibufpp != ',' && **ibufpp != ';' ) break;
274 if( **ibufpp == ';' ) set_current_addr( addr );
277 if( addr_cnt == 1 || second_addr != addr ) first_addr = second_addr;
278 return ( ( addr != -2 ) ? addr_cnt : -1 );
282 /* get a valid address from the command buffer */
283 static bool get_third_addr( const char ** const ibufpp, int * const addr )
285 const int old1 = first_addr;
286 const int old2 = second_addr;
287 int addr_cnt = extract_addr_range( ibufpp );
289 if( addr_cnt < 0 ) return false;
290 if( traditional() && addr_cnt == 0 )
291 { set_error_msg( "Destination expected" ); return false; }
292 if( second_addr < 0 || second_addr > last_addr() )
293 { invalid_address(); return false; }
295 first_addr = old1; second_addr = old2;
300 /* return true if address range is valid */
301 static bool check_addr_range( const int n, const int m, const int addr_cnt )
308 if( first_addr < 1 || first_addr > second_addr || second_addr > last_addr() )
309 { invalid_address(); return false; }
314 /* return true if current address is valid */
315 static bool check_current_addr( const int addr_cnt )
317 return check_addr_range( current_addr(), current_addr(), addr_cnt );
321 /* verify the command suffix in the command buffer */
322 static bool get_command_suffix( const char ** const ibufpp,
323 int * const gflagsp )
327 const char ch = **ibufpp;
328 if( ch == 'l' ) *gflagsp |= GLS;
329 else if( ch == 'n' ) *gflagsp |= GNP;
330 else if( ch == 'p' ) *gflagsp |= GPR;
334 if( *(*ibufpp)++ != '\n' )
335 { set_error_msg( "Invalid command suffix" ); return false; }
340 static bool unexpected_address( const int addr_cnt )
342 if( addr_cnt > 0 ) { set_error_msg( "Unexpected address" ); return true; }
346 static bool unexpected_command_suffix( const unsigned char ch )
349 { set_error_msg( "Unexpected command suffix" ); return true; }
354 static bool command_s( const char ** const ibufpp, int * const gflagsp,
355 const int addr_cnt, const bool isglobal )
357 static int gflags = 0;
360 SGG = 0x01, /* complement previous global substitute suffix */
361 SGP = 0x02, /* complement previous print suffix */
362 SGR = 0x04, /* use last regex instead of last pat */
363 SGF = 0x08 /* repeat last substitution */
367 if( isdigit( (unsigned char)**ibufpp ) )
369 if( !parse_int( &snum, *ibufpp, ibufpp ) ) return false;
370 sflags |= SGF; gflags &= ~GSG; /* override GSG */
372 else switch( **ibufpp )
374 case '\n':sflags |= SGF; break;
375 case 'g': sflags |= SGG; ++*ibufpp; break;
376 case 'p': sflags |= SGP; ++*ibufpp; break;
377 case 'r': sflags |= SGR; ++*ibufpp; break;
378 default : if( sflags )
379 { set_error_msg( "Invalid command suffix" ); return false; }
382 while( sflags && **ibufpp != '\n' );
383 if( sflags && !prev_pattern() )
384 { set_error_msg( "No previous substitution" ); return false; }
385 if( sflags & SGG ) snum = 0; /* override numeric arg */
386 if( **ibufpp != '\n' && (*ibufpp)[1] == '\n' )
387 { set_error_msg( "Invalid pattern delimiter" ); return false; }
388 if( ( !sflags || ( sflags & SGR ) ) && !new_compiled_pattern( ibufpp ) )
390 if( !sflags && !extract_subst_tail( ibufpp, &gflags, &snum, isglobal ) )
392 if( isglobal ) gflags |= GLB;
394 if( sflags & SGG ) gflags ^= GSG;
395 if( sflags & SGP ) { gflags ^= GPR; gflags &= ~( GLS | GNP ); }
398 case 'l': gflags |= GLS; ++*ibufpp; break;
399 case 'n': gflags |= GNP; ++*ibufpp; break;
400 case 'p': gflags |= GPR; ++*ibufpp; break;
402 if( !check_current_addr( addr_cnt ) ||
403 !get_command_suffix( ibufpp, gflagsp ) ) return false;
404 if( !isglobal ) clear_undo_stack();
405 if( !search_and_replace( first_addr, second_addr, gflags, snum, isglobal ) )
407 if( ( gflags & ( GPR | GLS | GNP ) ) &&
408 !display_lines( current_addr(), current_addr(), gflags ) )
414 static bool exec_global( const char ** const ibufpp, const int gflags,
415 const bool interactive );
417 /* execute the next command in command buffer; return error status */
418 static int exec_command( const char ** const ibufpp, const int prev_status,
419 const bool isglobal )
424 const int addr_cnt = extract_addr_range( ibufpp );
426 if( addr_cnt < 0 ) return ERR;
427 *ibufpp = skip_blanks( *ibufpp );
431 case 'a': if( !get_command_suffix( ibufpp, &gflags ) ) return ERR;
432 if( !isglobal ) clear_undo_stack();
433 if( !append_lines( ibufpp, second_addr, isglobal ) ) return ERR;
435 case 'c': if( first_addr == 0 ) first_addr = 1;
436 if( second_addr == 0 ) second_addr = 1;
437 if( !check_current_addr( addr_cnt ) ||
438 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
439 if( !isglobal ) clear_undo_stack();
440 if( !delete_lines( first_addr, second_addr, isglobal ) ||
441 !append_lines( ibufpp, current_addr(), isglobal ) ) return ERR;
443 case 'd': if( !check_current_addr( addr_cnt ) ||
444 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
445 if( !isglobal ) clear_undo_stack();
446 if( !delete_lines( first_addr, second_addr, isglobal ) ) return ERR;
449 case 'e': if( modified() && !scripted() && prev_status != EMOD )
450 return EMOD; /* fall through */
451 case 'E': if( unexpected_address( addr_cnt ) ||
452 unexpected_command_suffix( **ibufpp ) ) return ERR;
453 fnp = get_filename( ibufpp );
454 if( !fnp || !delete_lines( 1, last_addr(), isglobal ) ||
455 !close_sbuf() ) return ERR;
456 if( !open_sbuf() ) return FATAL;
457 if( fnp[0] && fnp[0] != '!' ) set_def_filename( fnp );
458 if( traditional() && !fnp[0] && !def_filename[0] )
459 { set_error_msg( "No current filename" ); return ERR; }
460 if( read_file( fnp[0] ? fnp : def_filename, 0 ) < 0 )
462 reset_undo_state(); set_modified( false );
464 case 'f': if( unexpected_address( addr_cnt ) ||
465 unexpected_command_suffix( **ibufpp ) ) return ERR;
466 fnp = get_filename( ibufpp );
467 if( !fnp ) return ERR;
469 { set_error_msg( "Invalid redirection" ); return ERR; }
470 if( fnp[0] ) set_def_filename( fnp );
471 printf( "%s\n", strip_escapes( def_filename ) );
476 case 'V': if( isglobal )
477 { set_error_msg( "Cannot nest global commands" ); return ERR; }
478 n = ( c == 'g' || c == 'G' ); /* mark matching lines */
479 if( !check_addr_range( 1, last_addr(), addr_cnt ) ||
480 !build_active_list( ibufpp, first_addr, second_addr, n ) )
482 n = ( c == 'G' || c == 'V' ); /* interactive */
483 if( ( n && !get_command_suffix( ibufpp, &gflags ) ) ||
484 !exec_global( ibufpp, gflags, n ) )
488 case 'H': if( unexpected_address( addr_cnt ) ||
489 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
490 if( c == 'H' ) verbose = !verbose;
491 if( ( c == 'h' || verbose ) && errmsg[0] )
492 fprintf( stderr, "%s\n", errmsg );
494 case 'i': if( second_addr == 0 ) second_addr = 1;
495 if( !get_command_suffix( ibufpp, &gflags ) ) return ERR;
496 if( !isglobal ) clear_undo_stack();
497 if( !append_lines( ibufpp, second_addr - 1, isglobal ) )
500 case 'j': if( !check_addr_range( current_addr(), current_addr() + 1, addr_cnt ) ||
501 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
502 if( !isglobal ) clear_undo_stack();
503 if( first_addr != second_addr &&
504 !join_lines( first_addr, second_addr, isglobal ) ) return ERR;
506 case 'k': n = *(*ibufpp)++;
507 if( second_addr == 0 ) { invalid_address(); return ERR; }
508 if( !get_command_suffix( ibufpp, &gflags ) ||
509 !mark_line_node( search_line_node( second_addr ), n ) )
514 case 'p': if( c == 'l' ) n = GLS; else if( c == 'n' ) n = GNP; else n = GPR;
515 if( !check_current_addr( addr_cnt ) ||
516 !get_command_suffix( ibufpp, &gflags ) ||
517 !display_lines( first_addr, second_addr, gflags | n ) )
521 case 'm': if( !check_current_addr( addr_cnt ) ||
522 !get_third_addr( ibufpp, &addr ) ) return ERR;
523 if( addr >= first_addr && addr < second_addr )
524 { set_error_msg( "Invalid destination" ); return ERR; }
525 if( !get_command_suffix( ibufpp, &gflags ) ) return ERR;
526 if( !isglobal ) clear_undo_stack();
527 if( !move_lines( first_addr, second_addr, addr, isglobal ) )
532 case 'Q': if( unexpected_address( addr_cnt ) ||
533 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
534 if( c == 'P' ) prompt_on = !prompt_on;
535 else if( modified() && !scripted() && c == 'q' &&
536 prev_status != EMOD ) return EMOD;
539 case 'r': if( unexpected_command_suffix( **ibufpp ) ) return ERR;
540 if( addr_cnt == 0 ) second_addr = last_addr();
541 fnp = get_filename( ibufpp );
542 if( !fnp ) return ERR;
543 if( !isglobal ) clear_undo_stack();
544 if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp );
545 if( traditional() && !fnp[0] && !def_filename[0] )
546 { set_error_msg( "No current filename" ); return ERR; }
547 addr = read_file( fnp[0] ? fnp : def_filename, second_addr );
548 if( addr < 0 ) return ERR;
549 if( addr ) set_modified( true );
551 case 's': if( !command_s( ibufpp, &gflags, addr_cnt, isglobal ) )
554 case 't': if( !check_current_addr( addr_cnt ) ||
555 !get_third_addr( ibufpp, &addr ) ||
556 !get_command_suffix( ibufpp, &gflags ) ) return ERR;
557 if( !isglobal ) clear_undo_stack();
558 if( !copy_lines( first_addr, second_addr, addr ) ) return ERR;
560 case 'u': if( unexpected_address( addr_cnt ) ||
561 !get_command_suffix( ibufpp, &gflags ) ||
562 !undo( isglobal ) ) return ERR;
565 case 'W': n = **ibufpp;
566 if( n == 'q' || n == 'Q' ) ++*ibufpp;
567 if( unexpected_command_suffix( **ibufpp ) ) return ERR;
568 fnp = get_filename( ibufpp );
569 if( !fnp ) return ERR;
570 if( addr_cnt == 0 && last_addr() == 0 )
571 first_addr = second_addr = 0;
572 else if( !check_addr_range( 1, last_addr(), addr_cnt ) )
574 if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp );
575 if( traditional() && !fnp[0] && !def_filename[0] )
576 { set_error_msg( "No current filename" ); return ERR; }
577 addr = write_file( fnp[0] ? fnp : def_filename,
578 ( c == 'W' ) ? "a" : "w", first_addr, second_addr );
579 if( addr < 0 ) return ERR;
580 if( addr == last_addr() ) set_modified( false );
581 else if( modified() && !scripted() && n == 'q' &&
582 prev_status != EMOD ) return EMOD;
583 if( n == 'q' || n == 'Q' ) return QUIT;
585 case 'x': if( second_addr < 0 || last_addr() < second_addr )
586 { invalid_address(); return ERR; }
587 if( !get_command_suffix( ibufpp, &gflags ) ) return ERR;
588 if( !isglobal ) clear_undo_stack();
589 if( !put_lines( second_addr ) ) return ERR;
591 case 'y': if( !check_current_addr( addr_cnt ) ||
592 !get_command_suffix( ibufpp, &gflags ) ||
593 !yank_lines( first_addr, second_addr ) ) return ERR;
595 case 'z': first_addr = 1;
596 if( !check_addr_range( first_addr, current_addr() +
597 ( traditional() || !isglobal ), addr_cnt ) )
599 if( **ibufpp > '0' && **ibufpp <= '9' )
600 { if( parse_int( &n, *ibufpp, ibufpp ) ) set_window_lines( n );
602 if( !get_command_suffix( ibufpp, &gflags ) ||
603 !display_lines( second_addr,
604 min( last_addr(), second_addr + window_lines() - 1 ),
609 case '=': if( !get_command_suffix( ibufpp, &gflags ) ) return ERR;
610 printf( "%d\n", addr_cnt ? second_addr : last_addr() );
612 case '!': if( unexpected_address( addr_cnt ) ) return ERR;
613 fnp = get_shell_command( ibufpp );
614 if( !fnp ) return ERR;
615 if( system( fnp + 1 ) < 0 )
616 { set_error_msg( "Can't create shell process" ); return ERR; }
617 if( !scripted() ) printf( "!\n" );
619 case '\n': first_addr = 1;
620 if( !check_addr_range( first_addr, current_addr() +
621 ( traditional() || !isglobal ), addr_cnt ) ||
622 !display_lines( second_addr, second_addr, 0 ) )
625 case '#': while( *(*ibufpp)++ != '\n' ) ;
627 default : set_error_msg( "Unknown command" ); return ERR;
629 if( gflags && !display_lines( current_addr(), current_addr(), gflags ) )
635 /* apply command list in the command buffer to the active lines in a
636 range; return false if error */
637 static bool exec_global( const char ** const ibufpp, const int gflags,
638 const bool interactive )
640 static char * buf = 0;
641 static int bufsz = 0;
642 const char * cmd = 0;
646 if( traditional() && !strcmp( *ibufpp, "\n" ) )
647 cmd = "p\n"; /* null cmd_list == 'p' */
650 if( !get_extended_line( ibufpp, 0, false ) ) return false;
657 const line_t * const lp = next_active_node();
659 set_current_addr( get_line_node_addr( lp ) );
660 if( current_addr() < 0 ) return false;
663 /* print current_addr; get a command in global syntax */
665 if( !display_lines( current_addr(), current_addr(), gflags ) )
667 do { *ibufpp = get_tty_line( &len ); }
668 while( *ibufpp && len > 0 && (*ibufpp)[len-1] != '\n' );
669 if( !*ibufpp ) return false;
671 { set_error_msg( "Unexpected end-of-file" ); return false; }
672 if( len == 1 && !strcmp( *ibufpp, "\n" ) ) continue;
673 if( len == 2 && !strcmp( *ibufpp, "&\n" ) )
674 { if( !cmd ) { set_error_msg( "No previous command" ); return false; } }
677 if( !get_extended_line( ibufpp, &len, false ) ||
678 !resize_buffer( &buf, &bufsz, len + 1 ) ) return false;
679 memcpy( buf, *ibufpp, len + 1 );
684 while( **ibufpp ) if( exec_command( ibufpp, 0, true ) < 0 ) return false;
690 int main_loop( const bool loose )
692 extern jmp_buf jmp_state;
693 const char * ibufp; /* pointer to command buffer */
694 volatile int err_status = 0; /* program exit status */
695 volatile int linenum = 0; /* script line number */
698 disable_interrupts();
700 status = setjmp( jmp_state );
701 if( !status ) enable_interrupts();
702 else { status = -1; fputs( "\n?\n", stderr ); set_error_msg( "Interrupt" ); }
707 if( status < 0 && verbose )
708 { fprintf( stderr, "%s\n", errmsg ); fflush( stderr ); }
709 if( prompt_on ) { printf( "%s", prompt_str ); fflush( stdout ); }
710 ibufp = get_tty_line( &len );
711 if( !ibufp ) return err_status;
714 if( !modified() || scripted() ) return err_status;
715 fputs( "?\n", stderr ); set_error_msg( "Warning: buffer modified" );
716 if( is_regular_file( 0 ) )
718 if( verbose ) fprintf( stderr, "script, line %d: %s\n", linenum, errmsg );
721 set_modified( false ); status = EMOD; continue;
723 else if( ibufp[len-1] != '\n' ) /* discard line */
724 { set_error_msg( "Unexpected end-of-file" ); status = ERR; continue; }
726 status = exec_command( &ibufp, status, false );
727 if( status == 0 ) continue;
728 if( status == QUIT ) return err_status;
731 fputs( "?\n", stderr ); /* give warning */
732 set_error_msg( "Warning: buffer modified" );
733 if( is_regular_file( 0 ) )
736 fprintf( stderr, "script, line %d: %s\n", linenum, errmsg );
740 else if( status == FATAL )
744 if( is_regular_file( 0 ) )
745 fprintf( stderr, "script, line %d: %s\n", linenum, errmsg );
746 else fprintf( stderr, "%s\n", errmsg );
752 fputs( "?\n", stderr ); /* give warning */
753 if( is_regular_file( 0 ) )
756 fprintf( stderr, "script, line %d: %s\n", linenum, errmsg );
760 if( !loose ) err_status = 1;