diff options
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | awk.h | 25 | ||||
-rw-r--r-- | awkgram.c | 11 | ||||
-rw-r--r-- | awkgram.y | 11 | ||||
-rw-r--r-- | debug.c | 23 | ||||
-rw-r--r-- | doc/gawk.info | 496 | ||||
-rw-r--r-- | doc/gawk.texi | 12 | ||||
-rw-r--r-- | eval.c | 378 | ||||
-rw-r--r-- | io.c | 25 | ||||
-rw-r--r-- | test/ChangeLog | 3 | ||||
-rw-r--r-- | test/Makefile.am | 14 | ||||
-rw-r--r-- | test/Makefile.in | 22 | ||||
-rw-r--r-- | test/Maketests | 5 | ||||
-rw-r--r-- | test/beginfile2.in | 242 | ||||
-rw-r--r-- | test/beginfile2.ok | 90 | ||||
-rwxr-xr-x | test/beginfile2.sh | 82 |
16 files changed, 1050 insertions, 417 deletions
@@ -1,3 +1,31 @@ +2011-08-10 John Haque <j.eh@mchsi.com> + + BEGINFILE/ENDFILE related code redone. + + * awk.h (prev_frame_size, has_endfile, target_get_record, + target_newfile): New defines. + * awkgram.y (mk_program): Initialize has_endfile appropriately for + Op_get_record. + (parse_program): Initialize new jump targets for + Op_get_record and Op_newfile. + * eval.c (unwind_stack): Change argument to number of + items to be left in the stack. Adjust code. + (pop_fcall, pop_stack): New defines. + (setup_frame): Initialize prev_frame_size. + (exec_state, EXEC_STATE): New structure and typedef. + (exec_state_stack): New variable. + (push_exec_state, pop_exec_state): New functions to save and + later retrieve an execution state. + (r_interpret): Use the new functions and the defines in + cases Op_K_getline, Op_after_beginfile, Op_after_endfile, + Op_newfile and Op_K_exit. + * io.c (after_beginfile): When skipping a file using nextfile, + return zero in case there was an error opening the file. + (has_endfile): Nuke global variable. + (inrec): Add a second argument to pass errno to the calling + routine. + * debug.c (print_instruction): Update cases. + 2011-08-10 Arnold D. Robbins <arnold@skeeve.com> Fix (apparently long-standing) problem with FIELDWIDTHS. @@ -304,6 +304,7 @@ typedef struct exp_node { struct { union { struct exp_node *lptr; + struct exp_instruction *li; long ll; } l; union { @@ -311,7 +312,7 @@ typedef struct exp_node { Regexp *preg; struct exp_node **av; void (*uptr)(void); - struct exp_instruction *iptr; + struct exp_instruction *ri; } r; union { struct exp_node *extra; @@ -391,7 +392,7 @@ typedef struct exp_node { #define param vname #define parmlist sub.nodep.x.param_list -#define code_ptr sub.nodep.r.iptr +#define code_ptr sub.nodep.r.ri #define re_reg sub.nodep.r.preg #define re_flags sub.nodep.reflags @@ -412,12 +413,13 @@ typedef struct exp_node { /* Node_frame: */ #define stack sub.nodep.r.av #define func_node sub.nodep.x.extra -#define reti sub.nodep.reflags +#define prev_frame_size sub.nodep.reflags +#define reti sub.nodep.l.li /* Node_var: */ #define var_value lnode #define var_update sub.nodep.r.uptr -#define var_assign sub.nodep.x.aptr +#define var_assign sub.nodep.x.aptr /* Node_var_array: */ #define var_array sub.nodep.r.av @@ -642,12 +644,21 @@ typedef struct exp_instruction { #define target_end d.di #define target_atexit x.xi -/* Op_newfile, Op_K_getline */ +/* Op_newfile, Op_K_getline, Op_nextfile */ #define target_endfile x.xi +/* Op_newfile */ +#define target_get_record x.xi + +/* Op_get_record, Op_K_nextfile */ +#define target_newfile d.di + /* Op_K_getline */ #define target_beginfile d.di +/* Op_get_record */ +#define has_endfile x.xl + /* Op_token */ #define lextok d.name @@ -687,7 +698,7 @@ typedef struct exp_instruction { #define func_body x.xn /* Op_func_call */ -#define inrule d.dl +#define inrule d.dl /* Op_subscript */ #define sub_count d.dl @@ -1306,7 +1317,7 @@ extern char *find_source(const char *src, struct stat *stb, int *errcode); extern NODE *do_getline_redir(int intovar, int redirtype); extern NODE *do_getline(int intovar, IOBUF *iop); extern struct redirect *getredirect(const char *str, int len); -extern int inrec(IOBUF *iop); +extern int inrec(IOBUF *iop, int *errcode); extern int nextfile(IOBUF **curfile, int skipping); /* main.c */ extern int arg_assign(char *arg, int initing); @@ -2855,7 +2855,7 @@ regular_loop: error_ln((yyvsp[(1) - (2)])->source_line, _("`nextfile' used in %s action"), ruletab[rule]); - (yyvsp[(1) - (2)])->target_jmp = ip_newfile; + (yyvsp[(1) - (2)])->target_newfile = ip_newfile; (yyvsp[(1) - (2)])->target_endfile = ip_endfile; (yyval) = list_create((yyvsp[(1) - (2)])); } @@ -4821,8 +4821,7 @@ mk_program() if (endfile_block == NULL) endfile_block = list_create(ip_endfile); else { - extern int has_endfile; /* kludge for use in inrec (io.c) */ - has_endfile = TRUE; + ip_rec->has_endfile = TRUE; (void) list_prepend(endfile_block, ip_endfile); } @@ -4914,10 +4913,12 @@ parse_program(INSTRUCTION **pcode) else { ip_endfile = instruction(Op_no_op); ip_beginfile = instruction(Op_no_op); - ip_newfile = instruction(Op_newfile); /* target for `nextfile' */ + ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */ + ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */ ip_newfile->target_jmp = ip_end; ip_newfile->target_endfile = ip_endfile; - ip_rec = instruction(Op_get_record); /* target for `next' */ + (ip_newfile + 1)->target_get_record = ip_rec; + ip_rec->target_newfile = ip_newfile; ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ } @@ -840,7 +840,7 @@ non_compound_stmt error_ln($1->source_line, _("`nextfile' used in %s action"), ruletab[rule]); - $1->target_jmp = ip_newfile; + $1->target_newfile = ip_newfile; $1->target_endfile = ip_endfile; $$ = list_create($1); } @@ -2131,8 +2131,7 @@ mk_program() if (endfile_block == NULL) endfile_block = list_create(ip_endfile); else { - extern int has_endfile; /* kludge for use in inrec (io.c) */ - has_endfile = TRUE; + ip_rec->has_endfile = TRUE; (void) list_prepend(endfile_block, ip_endfile); } @@ -2224,10 +2223,12 @@ parse_program(INSTRUCTION **pcode) else { ip_endfile = instruction(Op_no_op); ip_beginfile = instruction(Op_no_op); - ip_newfile = instruction(Op_newfile); /* target for `nextfile' */ + ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */ + ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */ ip_newfile->target_jmp = ip_end; ip_newfile->target_endfile = ip_endfile; - ip_rec = instruction(Op_get_record); /* target for `next' */ + (ip_newfile + 1)->target_get_record = ip_rec; + ip_rec->target_newfile = ip_newfile; ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ } @@ -3796,9 +3796,19 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_K_nextfile: + print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n", + pc->target_newfile, pc->target_endfile); + break; + case Op_newfile: print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n", pc->target_jmp, pc->target_endfile); + print_func(fp, "%*s[target_get_record = %p]\n", + noffset, "", (pc + 1)->target_get_record); + break; + + case Op_get_record: + print_func(fp, "[target_newfile = %p]\n", pc->target_newfile); break; case Op_jmp: @@ -5374,28 +5384,27 @@ pre_execute_code(INSTRUCTION **pi) return (ei == *pi); } -extern void unwind_stack(STACK_ITEM *sp_bottom); +extern INSTRUCTION *unwind_stack(long n); static NODE * execute_code(volatile INSTRUCTION *code) { volatile NODE *r = NULL; volatile jmp_buf fatal_tag_stack; - STACK_ITEM *ctxt_stack_bottom; + long save_stack_size; /* We use one global stack for all contexts. - * Remember stack bottom for current context; in case of - * a fatal error, unwind stack until stack_ptr is below that 'bottom'. + * Save # of items in stack; in case of + * a fatal error, pop stack until it has that many items. */ - ctxt_stack_bottom = stack_ptr + 1; + save_stack_size = (stack_ptr - stack_bottom) + 1; PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); if (setjmp(fatal_tag) == 0) { (void) r_interpret((INSTRUCTION *) code); - assert(stack_ptr == ctxt_stack_bottom); r = POP_SCALAR(); } else /* fatal error */ - unwind_stack(ctxt_stack_bottom); + (void) unwind_stack(save_stack_size); POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); diff --git a/doc/gawk.info b/doc/gawk.info index e344c401..70fb686b 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -8967,13 +8967,16 @@ implementations, or if `gawk' is in compatibility mode (*note Options::), `nextfile' is not special. Upon execution of the `nextfile' statement, any `ENDFILE' rules are -executed, `FILENAME' is updated to the name of the next data file -listed on the command line, `FNR' is reset to one, `ARGIND' is -incremented, any `BEGINFILE' rules are executed, and processing starts -over with the first rule in the program. (`ARGIND' hasn't been -introduced yet. *Note Built-in Variables::.) If the `nextfile' -statement causes the end of the input to be reached, then the code in -any `END' rules is executed. *Note BEGIN/END::. +executed except in the case as mentioned below, `FILENAME' is updated +to the name of the next data file listed on the command line, `FNR' is +reset to one, `ARGIND' is incremented, any `BEGINFILE' rules are +executed, and processing starts over with the first rule in the program. +(`ARGIND' hasn't been introduced yet. *Note Built-in Variables::.) If +the `nextfile' statement causes the end of the input to be reached, +then the code in any `END' rules is executed. An exception to this is +when the `nextfile' is invoked during execution of any statement in an +`END' rule; In this case, it causes the program to stop immediately. +*Note BEGIN/END::. The `nextfile' statement is useful when there are many data files to process but it isn't necessary to process every record in every file. @@ -8983,7 +8986,8 @@ accomplishes this much more efficiently. In addition, `nextfile' is useful inside a `BEGINFILE' rule to skip over a file that would otherwise cause `gawk' to exit with a fatal -error. *Note BEGINFILE/ENDFILE::. +error. In this case, `ENDFILE' rules are not executed. *Note +BEGINFILE/ENDFILE::. While one might think that `close(FILENAME)' would accomplish the same as `nextfile', this isn't true. `close()' is reserved for closing @@ -26008,7 +26012,7 @@ Index * functions, user-defined, counts: Profiling. (line 132) * functions, user-defined, library of: Library Functions. (line 6) * functions, user-defined, next/nextfile statements and <1>: Nextfile Statement. - (line 40) + (line 44) * functions, user-defined, next/nextfile statements and: Next Statement. (line 45) * G-d: Acknowledgments. (line 81) @@ -26522,7 +26526,7 @@ Index * nextfile statement, BEGINFILE/ENDFILE patterns and: BEGINFILE/ENDFILE. (line 26) * nextfile statement, user-defined functions and: Nextfile Statement. - (line 40) + (line 44) * nexti debugger command: Dgawk Execution Control. (line 49) * NF variable <1>: Auto-set. (line 107) @@ -27622,241 +27626,241 @@ Node: Break Statement374114 Node: Continue Statement376104 Node: Next Statement377891 Node: Nextfile Statement380281 -Node: Exit Statement382578 -Node: Built-in Variables384994 -Node: User-modified386089 -Ref: User-modified-Footnote-1394115 -Node: Auto-set394177 -Ref: Auto-set-Footnote-1403468 -Node: ARGC and ARGV403673 -Node: Arrays407524 -Node: Array Basics409029 -Node: Array Intro409740 -Node: Reference to Elements414058 -Node: Assigning Elements416328 -Node: Array Example416819 -Node: Scanning an Array418551 -Node: Delete421217 -Ref: Delete-Footnote-1423652 -Node: Numeric Array Subscripts423709 -Node: Uninitialized Subscripts425892 -Node: Multi-dimensional427520 -Node: Multi-scanning430614 -Node: Arrays of Arrays432198 -Node: Functions436775 -Node: Built-in437597 -Node: Calling Built-in438675 -Node: Numeric Functions440663 -Ref: Numeric Functions-Footnote-1444428 -Ref: Numeric Functions-Footnote-2444785 -Ref: Numeric Functions-Footnote-3444833 -Node: String Functions445102 -Ref: String Functions-Footnote-1468599 -Ref: String Functions-Footnote-2468728 -Ref: String Functions-Footnote-3468976 -Node: Gory Details469063 -Ref: table-sub-escapes470742 -Ref: table-sub-posix-92472096 -Ref: table-sub-proposed473439 -Ref: table-posix-sub474789 -Ref: table-gensub-escapes476335 -Ref: Gory Details-Footnote-1477542 -Ref: Gory Details-Footnote-2477593 -Node: I/O Functions477744 -Ref: I/O Functions-Footnote-1484399 -Node: Time Functions484546 -Ref: Time Functions-Footnote-1495438 -Ref: Time Functions-Footnote-2495506 -Ref: Time Functions-Footnote-3495664 -Ref: Time Functions-Footnote-4495775 -Ref: Time Functions-Footnote-5495887 -Ref: Time Functions-Footnote-6496114 -Node: Bitwise Functions496380 -Ref: table-bitwise-ops496938 -Ref: Bitwise Functions-Footnote-1501098 -Node: Type Functions501282 -Node: I18N Functions501752 -Node: User-defined503379 -Node: Definition Syntax504183 -Ref: Definition Syntax-Footnote-1509093 -Node: Function Example509162 -Node: Function Caveats511756 -Node: Calling A Function512177 -Node: Variable Scope513292 -Node: Pass By Value/Reference515267 -Node: Return Statement518707 -Node: Dynamic Typing521688 -Node: Indirect Calls522423 -Node: Internationalization532108 -Node: I18N and L10N533534 -Node: Explaining gettext534220 -Ref: Explaining gettext-Footnote-1539286 -Ref: Explaining gettext-Footnote-2539470 -Node: Programmer i18n539635 -Node: Translator i18n543835 -Node: String Extraction544628 -Ref: String Extraction-Footnote-1545589 -Node: Printf Ordering545675 -Ref: Printf Ordering-Footnote-1548459 -Node: I18N Portability548523 -Ref: I18N Portability-Footnote-1550972 -Node: I18N Example551035 -Ref: I18N Example-Footnote-1553670 -Node: Gawk I18N553742 -Node: Advanced Features554359 -Node: Nondecimal Data555872 -Node: Array Sorting557455 -Node: Controlling Array Traversal558155 -Node: Controlling Scanning With A Function558902 -Node: Controlling Scanning566605 -Ref: Controlling Scanning-Footnote-1570406 -Node: Array Sorting Functions570722 -Ref: Array Sorting Functions-Footnote-1574238 -Ref: Array Sorting Functions-Footnote-2574331 -Node: Two-way I/O574525 -Ref: Two-way I/O-Footnote-1579957 -Node: TCP/IP Networking580027 -Node: Profiling582871 -Node: Library Functions590345 -Ref: Library Functions-Footnote-1593352 -Node: Library Names593523 -Ref: Library Names-Footnote-1596994 -Ref: Library Names-Footnote-2597214 -Node: General Functions597300 -Node: Strtonum Function598253 -Node: Assert Function601183 -Node: Round Function604509 -Node: Cliff Random Function606052 -Node: Ordinal Functions607068 -Ref: Ordinal Functions-Footnote-1610138 -Ref: Ordinal Functions-Footnote-2610390 -Node: Join Function610599 -Ref: Join Function-Footnote-1612370 -Node: Gettimeofday Function612570 -Node: Data File Management616285 -Node: Filetrans Function616917 -Node: Rewind Function621056 -Node: File Checking622443 -Node: Empty Files623537 -Node: Ignoring Assigns625767 -Node: Getopt Function627320 -Ref: Getopt Function-Footnote-1638624 -Node: Passwd Functions638827 -Ref: Passwd Functions-Footnote-1647802 -Node: Group Functions647890 -Node: Walking Arrays655974 -Node: Sample Programs657543 -Node: Running Examples658208 -Node: Clones658936 -Node: Cut Program660160 -Node: Egrep Program670005 -Ref: Egrep Program-Footnote-1677778 -Node: Id Program677888 -Node: Split Program681504 -Ref: Split Program-Footnote-1685023 -Node: Tee Program685151 -Node: Uniq Program687954 -Node: Wc Program695383 -Ref: Wc Program-Footnote-1699649 -Ref: Wc Program-Footnote-2699849 -Node: Miscellaneous Programs699941 -Node: Dupword Program701129 -Node: Alarm Program703160 -Node: Translate Program707909 -Ref: Translate Program-Footnote-1712296 -Ref: Translate Program-Footnote-2712524 -Node: Labels Program712658 -Ref: Labels Program-Footnote-1716029 -Node: Word Sorting716113 -Node: History Sorting719997 -Node: Extract Program721836 -Ref: Extract Program-Footnote-1729319 -Node: Simple Sed729447 -Node: Igawk Program732509 -Ref: Igawk Program-Footnote-1747666 -Ref: Igawk Program-Footnote-2747867 -Node: Anagram Program748005 -Node: Signature Program751073 -Node: Debugger752173 -Node: Debugging753084 -Node: Debugging Concepts753497 -Node: Debugging Terms755353 -Node: Awk Debugging757976 -Node: Sample dgawk session758868 -Node: dgawk invocation759360 -Node: Finding The Bug760542 -Node: List of Debugger Commands767028 -Node: Breakpoint Control768339 -Node: Dgawk Execution Control771975 -Node: Viewing And Changing Data775326 -Node: Dgawk Stack778663 -Node: Dgawk Info780123 -Node: Miscellaneous Dgawk Commands784071 -Node: Readline Support789499 -Node: Dgawk Limitations790337 -Node: Language History792526 -Node: V7/SVR3.1794038 -Node: SVR4796359 -Node: POSIX797801 -Node: BTL798809 -Node: POSIX/GNU799543 -Node: Common Extensions804694 -Node: Ranges and Locales805801 -Ref: Ranges and Locales-Footnote-1810408 -Node: Contributors810629 -Node: Installation814891 -Node: Gawk Distribution815785 -Node: Getting816269 -Node: Extracting817095 -Node: Distribution contents818787 -Node: Unix Installation824009 -Node: Quick Installation824626 -Node: Additional Configuration Options826588 -Node: Configuration Philosophy828065 -Node: Non-Unix Installation830407 -Node: PC Installation830865 -Node: PC Binary Installation832164 -Node: PC Compiling834012 -Node: PC Testing836956 -Node: PC Using838132 -Node: Cygwin842317 -Node: MSYS843317 -Node: VMS Installation843831 -Node: VMS Compilation844434 -Ref: VMS Compilation-Footnote-1845441 -Node: VMS Installation Details845499 -Node: VMS Running847134 -Node: VMS Old Gawk848741 -Node: Bugs849215 -Node: Other Versions853068 -Node: Notes858349 -Node: Compatibility Mode859041 -Node: Additions859824 -Node: Accessing The Source860636 -Node: Adding Code862061 -Node: New Ports868028 -Node: Dynamic Extensions872141 -Node: Internals873517 -Node: Plugin License882620 -Node: Sample Library883254 -Node: Internal File Description883940 -Node: Internal File Ops887655 -Ref: Internal File Ops-Footnote-1892436 -Node: Using Internal File Ops892576 -Node: Future Extensions894953 -Node: Basic Concepts897457 -Node: Basic High Level898214 -Ref: Basic High Level-Footnote-1902249 -Node: Basic Data Typing902434 -Node: Floating Point Issues906959 -Node: String Conversion Precision908042 -Ref: String Conversion Precision-Footnote-1909742 -Node: Unexpected Results909851 -Node: POSIX Floating Point Problems911677 -Ref: POSIX Floating Point Problems-Footnote-1915382 -Node: Glossary915420 -Node: Copying940396 -Node: GNU Free Documentation License977953 -Node: Index1003090 +Node: Exit Statement382826 +Node: Built-in Variables385242 +Node: User-modified386337 +Ref: User-modified-Footnote-1394363 +Node: Auto-set394425 +Ref: Auto-set-Footnote-1403716 +Node: ARGC and ARGV403921 +Node: Arrays407772 +Node: Array Basics409277 +Node: Array Intro409988 +Node: Reference to Elements414306 +Node: Assigning Elements416576 +Node: Array Example417067 +Node: Scanning an Array418799 +Node: Delete421465 +Ref: Delete-Footnote-1423900 +Node: Numeric Array Subscripts423957 +Node: Uninitialized Subscripts426140 +Node: Multi-dimensional427768 +Node: Multi-scanning430862 +Node: Arrays of Arrays432446 +Node: Functions437023 +Node: Built-in437845 +Node: Calling Built-in438923 +Node: Numeric Functions440911 +Ref: Numeric Functions-Footnote-1444676 +Ref: Numeric Functions-Footnote-2445033 +Ref: Numeric Functions-Footnote-3445081 +Node: String Functions445350 +Ref: String Functions-Footnote-1468847 +Ref: String Functions-Footnote-2468976 +Ref: String Functions-Footnote-3469224 +Node: Gory Details469311 +Ref: table-sub-escapes470990 +Ref: table-sub-posix-92472344 +Ref: table-sub-proposed473687 +Ref: table-posix-sub475037 +Ref: table-gensub-escapes476583 +Ref: Gory Details-Footnote-1477790 +Ref: Gory Details-Footnote-2477841 +Node: I/O Functions477992 +Ref: I/O Functions-Footnote-1484647 +Node: Time Functions484794 +Ref: Time Functions-Footnote-1495686 +Ref: Time Functions-Footnote-2495754 +Ref: Time Functions-Footnote-3495912 +Ref: Time Functions-Footnote-4496023 +Ref: Time Functions-Footnote-5496135 +Ref: Time Functions-Footnote-6496362 +Node: Bitwise Functions496628 +Ref: table-bitwise-ops497186 +Ref: Bitwise Functions-Footnote-1501346 +Node: Type Functions501530 +Node: I18N Functions502000 +Node: User-defined503627 +Node: Definition Syntax504431 +Ref: Definition Syntax-Footnote-1509341 +Node: Function Example509410 +Node: Function Caveats512004 +Node: Calling A Function512425 +Node: Variable Scope513540 +Node: Pass By Value/Reference515515 +Node: Return Statement518955 +Node: Dynamic Typing521936 +Node: Indirect Calls522671 +Node: Internationalization532356 +Node: I18N and L10N533782 +Node: Explaining gettext534468 +Ref: Explaining gettext-Footnote-1539534 +Ref: Explaining gettext-Footnote-2539718 +Node: Programmer i18n539883 +Node: Translator i18n544083 +Node: String Extraction544876 +Ref: String Extraction-Footnote-1545837 +Node: Printf Ordering545923 +Ref: Printf Ordering-Footnote-1548707 +Node: I18N Portability548771 +Ref: I18N Portability-Footnote-1551220 +Node: I18N Example551283 +Ref: I18N Example-Footnote-1553918 +Node: Gawk I18N553990 +Node: Advanced Features554607 +Node: Nondecimal Data556120 +Node: Array Sorting557703 +Node: Controlling Array Traversal558403 +Node: Controlling Scanning With A Function559150 +Node: Controlling Scanning566853 +Ref: Controlling Scanning-Footnote-1570654 +Node: Array Sorting Functions570970 +Ref: Array Sorting Functions-Footnote-1574486 +Ref: Array Sorting Functions-Footnote-2574579 +Node: Two-way I/O574773 +Ref: Two-way I/O-Footnote-1580205 +Node: TCP/IP Networking580275 +Node: Profiling583119 +Node: Library Functions590593 +Ref: Library Functions-Footnote-1593600 +Node: Library Names593771 +Ref: Library Names-Footnote-1597242 +Ref: Library Names-Footnote-2597462 +Node: General Functions597548 +Node: Strtonum Function598501 +Node: Assert Function601431 +Node: Round Function604757 +Node: Cliff Random Function606300 +Node: Ordinal Functions607316 +Ref: Ordinal Functions-Footnote-1610386 +Ref: Ordinal Functions-Footnote-2610638 +Node: Join Function610847 +Ref: Join Function-Footnote-1612618 +Node: Gettimeofday Function612818 +Node: Data File Management616533 +Node: Filetrans Function617165 +Node: Rewind Function621304 +Node: File Checking622691 +Node: Empty Files623785 +Node: Ignoring Assigns626015 +Node: Getopt Function627568 +Ref: Getopt Function-Footnote-1638872 +Node: Passwd Functions639075 +Ref: Passwd Functions-Footnote-1648050 +Node: Group Functions648138 +Node: Walking Arrays656222 +Node: Sample Programs657791 +Node: Running Examples658456 +Node: Clones659184 +Node: Cut Program660408 +Node: Egrep Program670253 +Ref: Egrep Program-Footnote-1678026 +Node: Id Program678136 +Node: Split Program681752 +Ref: Split Program-Footnote-1685271 +Node: Tee Program685399 +Node: Uniq Program688202 +Node: Wc Program695631 +Ref: Wc Program-Footnote-1699897 +Ref: Wc Program-Footnote-2700097 +Node: Miscellaneous Programs700189 +Node: Dupword Program701377 +Node: Alarm Program703408 +Node: Translate Program708157 +Ref: Translate Program-Footnote-1712544 +Ref: Translate Program-Footnote-2712772 +Node: Labels Program712906 +Ref: Labels Program-Footnote-1716277 +Node: Word Sorting716361 +Node: History Sorting720245 +Node: Extract Program722084 +Ref: Extract Program-Footnote-1729567 +Node: Simple Sed729695 +Node: Igawk Program732757 +Ref: Igawk Program-Footnote-1747914 +Ref: Igawk Program-Footnote-2748115 +Node: Anagram Program748253 +Node: Signature Program751321 +Node: Debugger752421 +Node: Debugging753332 +Node: Debugging Concepts753745 +Node: Debugging Terms755601 +Node: Awk Debugging758224 +Node: Sample dgawk session759116 +Node: dgawk invocation759608 +Node: Finding The Bug760790 +Node: List of Debugger Commands767276 +Node: Breakpoint Control768587 +Node: Dgawk Execution Control772223 +Node: Viewing And Changing Data775574 +Node: Dgawk Stack778911 +Node: Dgawk Info780371 +Node: Miscellaneous Dgawk Commands784319 +Node: Readline Support789747 +Node: Dgawk Limitations790585 +Node: Language History792774 +Node: V7/SVR3.1794286 +Node: SVR4796607 +Node: POSIX798049 +Node: BTL799057 +Node: POSIX/GNU799791 +Node: Common Extensions804942 +Node: Ranges and Locales806049 +Ref: Ranges and Locales-Footnote-1810656 +Node: Contributors810877 +Node: Installation815139 +Node: Gawk Distribution816033 +Node: Getting816517 +Node: Extracting817343 +Node: Distribution contents819035 +Node: Unix Installation824257 +Node: Quick Installation824874 +Node: Additional Configuration Options826836 +Node: Configuration Philosophy828313 +Node: Non-Unix Installation830655 +Node: PC Installation831113 +Node: PC Binary Installation832412 +Node: PC Compiling834260 +Node: PC Testing837204 +Node: PC Using838380 +Node: Cygwin842565 +Node: MSYS843565 +Node: VMS Installation844079 +Node: VMS Compilation844682 +Ref: VMS Compilation-Footnote-1845689 +Node: VMS Installation Details845747 +Node: VMS Running847382 +Node: VMS Old Gawk848989 +Node: Bugs849463 +Node: Other Versions853316 +Node: Notes858597 +Node: Compatibility Mode859289 +Node: Additions860072 +Node: Accessing The Source860884 +Node: Adding Code862309 +Node: New Ports868276 +Node: Dynamic Extensions872389 +Node: Internals873765 +Node: Plugin License882868 +Node: Sample Library883502 +Node: Internal File Description884188 +Node: Internal File Ops887903 +Ref: Internal File Ops-Footnote-1892684 +Node: Using Internal File Ops892824 +Node: Future Extensions895201 +Node: Basic Concepts897705 +Node: Basic High Level898462 +Ref: Basic High Level-Footnote-1902497 +Node: Basic Data Typing902682 +Node: Floating Point Issues907207 +Node: String Conversion Precision908290 +Ref: String Conversion Precision-Footnote-1909990 +Node: Unexpected Results910099 +Node: POSIX Floating Point Problems911925 +Ref: POSIX Floating Point Problems-Footnote-1915630 +Node: Glossary915668 +Node: Copying940644 +Node: GNU Free Documentation License978201 +Node: Index1003338 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 87d8ff2e..9dbd45c0 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -12161,16 +12161,17 @@ or if @command{gawk} is in compatibility mode @code{nextfile} is not special. Upon execution of the @code{nextfile} statement, -any @code{ENDFILE} rules are executed, -@code{FILENAME} is +any @code{ENDFILE} rules are executed except in the case as +mentioned below, @code{FILENAME} is updated to the name of the next @value{DF} listed on the command line, @code{FNR} is reset to one, @code{ARGIND} is incremented, any @code{BEGINFILE} rules are executed, and processing starts over with the first rule in the program. (@code{ARGIND} hasn't been introduced yet. @xref{Built-in Variables}.) If the @code{nextfile} statement causes the end of the input to be reached, -then the code in any @code{END} rules is executed. -@xref{BEGIN/END}. +then the code in any @code{END} rules is executed. An exception to this is +when the @code{nextfile} is invoked during execution of any statement in an +@code{END} rule; In this case, it causes the program to stop immediately. @xref{BEGIN/END}. The @code{nextfile} statement is useful when there are many @value{DF}s to process but it isn't necessary to process every record in every file. @@ -12180,7 +12181,8 @@ statement accomplishes this much more efficiently. In addition, @code{nextfile} is useful inside a @code{BEGINFILE} rule to skip over a file that would otherwise cause @command{gawk} -to exit with a fatal error. @xref{BEGINFILE/ENDFILE}. +to exit with a fatal error. In this case, @code{ENDFILE} rules are not +executed. @xref{BEGINFILE/ENDFILE}. While one might think that @samp{close(FILENAME)} would accomplish the same as @code{nextfile}, this isn't true. @code{close()} is @@ -30,7 +30,7 @@ extern double pow(double x, double y); extern double modf(double x, double *yp); extern double fmod(double x, double y); NODE **fcall_list; -long fcall_count; +long fcall_count = 0; int currule = 0; IOBUF *curfile = NULL; /* current data file */ int exiting = FALSE; @@ -678,7 +678,7 @@ pop_frame() #endif } #else /* not PROFILING or DEBUGGING */ -#define push_frame(p) /* nothing */ +#define push_frame(p) /* nothing */ #define pop_frame() /* nothing */ #endif @@ -690,7 +690,6 @@ pop_frame() void dump_fcall_stack(FILE *fp) { - NODE *f, *func; long i = 0; @@ -1150,12 +1149,6 @@ r_get_lhs(NODE *n, int reference) case Node_var: break; -#if 0 - case Node_builtin: - /* in gawk for a while */ - fatal(_("assignment is not allowed to result of builtin function")); -#endif - default: cant_happen(); } @@ -1242,7 +1235,7 @@ calc_exp(AWKNUM x1, AWKNUM x2) /* setup_frame --- setup new frame for function call */ -static void +static INSTRUCTION * setup_frame(INSTRUCTION *pc) { NODE *r = NULL; @@ -1329,18 +1322,23 @@ setup_frame(INSTRUCTION *pc) DEREF(r); } + frame_ptr->vname = source; /* save current source */ + push_frame(frame_ptr); /* save current frame in stack */ PUSH(frame_ptr); + /* setup new frame */ getnode(frame_ptr); frame_ptr->type = Node_frame; frame_ptr->stack = sp; + frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */ frame_ptr->func_node = f; frame_ptr->vname = NULL; + frame_ptr->reti = pc; /* on return execute pc->nexti */ - frame_ptr->reti = (unsigned long) pc; /* on return execute pc->nexti */ + return f->code_ptr; } @@ -1369,13 +1367,18 @@ restore_frame(NODE *fp) } if (frame_ptr->stack != NULL) efree(frame_ptr->stack); - ri = (INSTRUCTION *) frame_ptr->reti; /* execution in calling frame - * resumes from ri->nexti. - */ + ri = frame_ptr->reti; /* execution in calling frame + * resumes from ri->nexti. + */ freenode(frame_ptr); pop_frame(); + /* restore frame */ frame_ptr = fp; + /* restore source */ + source = fp->vname; + fp->vname = NULL; + return ri->nexti; } @@ -1395,33 +1398,40 @@ free_arrayfor(NODE *r) freenode(r); } -/* unwind_stack --- pop the runtime stack */ -void -unwind_stack(STACK_ITEM *sp_bottom) +/* unwind_stack --- pop items off the run-time stack; + * 'n' is the # of items left in the stack. + */ + +INSTRUCTION * +unwind_stack(long n) { NODE *r; + INSTRUCTION *cp = NULL; + STACK_ITEM *sp; - while (stack_ptr >= sp_bottom) { - r = POP(); - switch (r->type) { - case Node_instruction: - freenode(r); - break; + if (stack_empty()) + return NULL; + + sp = stack_bottom + n; + + if (stack_ptr < sp) + return NULL; + while (r = POP()) { + switch (r->type) { case Node_frame: - (void) restore_frame(r); - source = frame_ptr->vname; + cp = restore_frame(r); break; - case Node_arrayfor: free_arrayfor(r); break; - case Node_val: DEREF(r); break; - + case Node_instruction: + freenode(r); + break; default: if (in_main_context()) fatal(_("unwind_stack: unexpected type `%s'"), @@ -1435,8 +1445,19 @@ unwind_stack(STACK_ITEM *sp_bottom) */ break; } + + if (stack_ptr < sp) + break; } -} + return cp; +} + + +/* pop_fcall --- pop off the innermost frame */ +#define pop_fcall() unwind_stack(frame_ptr->prev_frame_size) + +/* pop the run-time stack */ +#define pop_stack() (void) unwind_stack(0) /* @@ -1563,6 +1584,75 @@ POP_CODE() } +/* Implementation of BEGINFILE and ENDFILE requires saving an execution + * state and the ability to return to that state. The state is + * defined by the instruction triggering the BEGINFILE/ENDFILE rule, the + * run-time stack, the rule and the source file. The source line is available in + * the instruction and hence is not considered a part of the execution state. + */ + + +typedef struct exec_state { + struct exec_state *next; + + INSTRUCTION *cptr; /* either getline (Op_K_getline) or the + * implicit "open-file, read-record" loop (Op_newfile). + */ + + int rule; /* rule for the INSTRUCTION */ + + long stack_size; /* For this particular usage, it is sufficient to save + * only the size of the call stack. We do not + * store the actual stack pointer to avoid problems + * in case the stack gets realloc-ed. + */ + + const char *source; /* source file for the INSTRUCTION */ +} EXEC_STATE; + +static EXEC_STATE exec_state_stack; + +/* push_exec_state --- save an execution state on stack */ + +static void +push_exec_state(INSTRUCTION *cp, int rule, char *src, STACK_ITEM *sp) +{ + EXEC_STATE *es; + + emalloc(es, EXEC_STATE *, sizeof(EXEC_STATE), "push_exec_state"); + es->rule = rule; + es->cptr = cp; + es->stack_size = (sp - stack_bottom) + 1; + es->source = src; + es->next = exec_state_stack.next; + exec_state_stack.next = es; +} + + +/* pop_exec_state --- pop one execution state off the stack */ + +static INSTRUCTION * +pop_exec_state(int *rule, char **src, long *sz) +{ + INSTRUCTION *cp; + EXEC_STATE *es; + + es = exec_state_stack.next; + if (es == NULL) + return NULL; + cp = es->cptr; + if (rule != NULL) + *rule = es->rule; + if (src != NULL) + *src = (char *) es->source; + if (sz != NULL) + *sz = es->stack_size; + exec_state_stack.next = es->next; + efree(es); + return cp; +} + + /* * r_interpret: * code is a list of instructions to run. returns the exit value @@ -1598,6 +1688,7 @@ r_interpret(INSTRUCTION *code) #endif int stdio_problem = FALSE; + if (args_array == NULL) emalloc(args_array, NODE **, (max_args + 2)*sizeof(NODE *), "r_interpret"); else @@ -2227,7 +2318,7 @@ post: /* * Actual array for use in lint warning * in Op_arrayfor_incr - */ + */ list[num_elems] = array; arrayfor: @@ -2383,10 +2474,8 @@ match_re: /* save current frame along with source */ func_call: - frame_ptr->vname = source; /* save current source */ - setup_frame(pc); - - ni = f->code_ptr; /* function code */ + ni = setup_frame(pc); + if (ni->opcode == Op_ext_func) { /* dynamically set source and line numbers for an extension builtin. */ ni->source_file = source; @@ -2401,29 +2490,11 @@ func_call: case Op_K_return: m = POP_SCALAR(); /* return value */ - r = POP(); - while (r->type != Node_frame) { - switch (r->type) { - case Node_arrayfor: - free_arrayfor(r); - break; - case Node_val: - DEREF(r); - break; - case Node_instruction: - freenode(r); - break; - default: - break; - } - r = POP(); - } - - ni = restore_frame(r); - source = frame_ptr->vname; - + ni = pop_fcall(); + /* put the return value back on stack */ PUSH(m); + JUMPTO(ni); case Op_K_getline_redir: @@ -2439,13 +2510,20 @@ func_call: if (currule == BEGINFILE || currule == ENDFILE) fatal(_("non-redirected `getline' invalid inside `%s' rule"), ruletab[currule]); + do { int ret; - ret = nextfile(&curfile, FALSE); + ret = nextfile(& curfile, FALSE); if (ret <= 0) r = do_getline(pc->into_var, curfile); else { - PUSH_CODE(pc); + + /* Save execution state so that we can return to it + * from Op_after_beginfile or Op_after_endfile. + */ + + push_exec_state(pc, currule, source, stack_ptr); + if (curfile == NULL) JUMPTO((pc + 1)->target_endfile); else @@ -2457,84 +2535,125 @@ func_call: break; case Op_after_endfile: - ni = POP_CODE(); + /* Find the execution state to return to */ + ni = pop_exec_state(& currule, & source, NULL); + assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline); JUMPTO(ni); case Op_after_beginfile: - after_beginfile(&curfile); - ni = POP_CODE(); + after_beginfile(& curfile); + + /* Find the execution state to return to */ + ni = pop_exec_state(& currule, & source, NULL); + + assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline); if (ni->opcode == Op_K_getline || curfile == NULL /* skipping directory argument */ ) JUMPTO(ni); - PUSH_CODE(ni); /* for use in Op_K_nextfile and Op_get_record */ - break; /* Op_get_record */ + + break; /* read a record, Op_get_record */ case Op_newfile: { int ret; - ret = nextfile(&curfile, FALSE); - if (ret < 0) - JUMPTO(pc->target_jmp); /* end block or Op_atexit */ - else if (ret > 0) { - PUSH_CODE(pc); - if (curfile == NULL) - JUMPTO(pc->target_endfile); - break; /* beginfile block */ - } else - PUSH_CODE(pc); - /* fall through */ + + ret = nextfile(& curfile, FALSE); + + if (ret < 0) /* end of input */ + JUMPTO(pc->target_jmp); /* end block or Op_atexit */ + + if (ret == 0) /* read a record */ + JUMPTO((pc + 1)->target_get_record); + + /* ret > 0 */ + /* Save execution state for use in Op_after_beginfile or Op_after_endfile. */ + + push_exec_state(pc, currule, source, stack_ptr); + + if (curfile == NULL) /* EOF */ + JUMPTO(pc->target_endfile); + /* else + execute beginfile block */ } + break; - case Op_get_record: - if (curfile == NULL) { /* from getline without redirection */ - ni = POP_CODE(); /* Op_newfile */ - ni = ni->target_jmp; /* end_block or Op_atexit */ - } else if (inrec(curfile) == 0) - break; /* prog(rule) block */ - else - ni = POP_CODE(); /* Op_newfile */ - JUMPTO(ni); + case Op_get_record: + { + int errcode = 0; + + ni = pc->target_newfile; + if (curfile == NULL) { + /* from non-redirected getline, e.g.: + * { + * while (getline > 0) ; + * } + */ + + ni = ni->target_jmp; /* end_block or Op_atexit */ + JUMPTO(ni); + } + + if (inrec(curfile, & errcode) != 0) { + if (errcode > 0 && (do_traditional || ! pc->has_endfile)) + fatal(_("error reading input file `%s': %s"), + curfile->name, strerror(errcode)); + + JUMPTO(ni); + } /* else + prog (rule) block */ + } + break; case Op_K_nextfile: + { + int ret; + if (currule != Rule && currule != BEGINFILE) - fatal(_("`nextfile' cannot be called from a `%s' rule"), ruletab[currule]); - (void) nextfile(&curfile, TRUE); - while (currule == BEGINFILE) { - r = POP(); - switch (r->type) { - case Node_instruction: - ni = r->code_ptr; - freenode(r); - if (ni->opcode == Op_newfile || ni->opcode == Op_K_getline) - JUMPTO(ni); - break; - case Node_frame: - (void) restore_frame(r); - source = frame_ptr->vname; - break; - case Node_arrayfor: - free_arrayfor(r); - break; - case Node_val: - DEREF(r); - break; - default: - break; - } - } + fatal(_("`nextfile' cannot be called from a `%s' rule"), + ruletab[currule]); - assert(currule != BEGINFILE); - unwind_stack(stack_bottom + 1); /* don't pop Op_newfile */ - JUMPTO(pc->target_endfile); /* endfile block */ + ret = nextfile(& curfile, TRUE); /* skip current file */ - case Op_K_exit: - if (currule == END) - ni = pc->target_atexit; - else - ni = pc->target_end; + if (currule == BEGINFILE) { + long stack_size; + + ni = pop_exec_state(& currule, & source, & stack_size); + + assert(ni->opcode == Op_K_getline || ni->opcode == Op_newfile); + + /* pop stack returning to the state of Op_K_getline or Op_newfile. */ + unwind_stack(stack_size); + + if (ret == 0) { + /* There was an error opening the file; + * don't run ENDFILE block(s). + */ + + JUMPTO(ni); + } else { + /* do run ENDFILE block(s) first. */ + + /* Execution state to return to in Op_after_endfile. */ + push_exec_state(ni, currule, source, stack_ptr); + + JUMPTO(pc->target_endfile); + } + } /* else + Start over with the first rule. */ + + /* empty the run-time stack to avoid memory leak */ + pop_stack(); + + /* Push an execution state for Op_after_endfile to return to */ + push_exec_state(pc->target_newfile, currule, source, stack_ptr); + JUMPTO(pc->target_endfile); + } + break; + + case Op_K_exit: exiting = TRUE; POP_NUMBER(x1); exit_val = (int) x1; @@ -2546,19 +2665,36 @@ func_call: /* else just pass anything else on through */ #endif - /* jump to either the first end_block instruction - * or to Op_atexit + + if (currule == BEGINFILE || currule == ENDFILE) { + + /* Find the rule of the saved execution state (Op_K_getline/Op_newfile). + * This is needed to prevent multiple execution of any END rules: + * gawk 'BEGINFILE { exit(1) } \ + * END { while (getline > 0); }' in1 in2 + */ + + (void) pop_exec_state(& currule, & source, NULL); + } + + pop_stack(); /* empty stack, don't leak memory */ + + /* Jump to either the first END block instruction + * or to Op_atexit. */ - unwind_stack(stack_bottom); + + if (currule == END) + ni = pc->target_atexit; + else + ni = pc->target_end; JUMPTO(ni); case Op_K_next: if (currule != Rule) fatal(_("`next' cannot be called from a `%s' rule"), ruletab[currule]); - /* jump to Op_get_record */ - unwind_stack(stack_bottom + 1); /* don't pop Op_newfile */ - JUMPTO(pc->target_jmp); + pop_stack(); + JUMPTO(pc->target_jmp); /* Op_get_record, read next record */ case Op_pop: #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) @@ -214,7 +214,6 @@ static Regexp *RS_re_no_case; static Regexp *RS_regexp; int RS_is_null; -int has_endfile = FALSE; extern int output_is_tty; extern NODE *ARGC_node; @@ -262,10 +261,6 @@ after_beginfile(IOBUF **curfile) iop = *curfile; assert(iop != NULL); -#if 0 - if (iop == NULL) - return; -#endif if (iop->fd == INVALID_HANDLE) { const char *fname; @@ -309,10 +304,13 @@ nextfile(IOBUF **curfile, int skipping) IOBUF *iop = *curfile; if (skipping) { /* for 'nextfile' call */ - if (iop != NULL) + errcode = 0; + if (iop != NULL) { + errcode = iop->errcode; (void) iop_close(iop); + } *curfile = NULL; - return 0; /* return value not used */ + return (errcode == 0); } if (iop != NULL) { @@ -409,28 +407,23 @@ set_NR() /* inrec --- This reads in a record from the input file */ int -inrec(IOBUF *iop) +inrec(IOBUF *iop, int *errcode) { char *begin; int cnt; int retval = 0; - int errcode = 0; if (at_eof(iop) && no_data_left(iop)) cnt = EOF; else if ((iop->flag & IOP_CLOSED) != 0) cnt = EOF; else - cnt = get_a_record(&begin, iop, & errcode); + cnt = get_a_record(&begin, iop, errcode); if (cnt == EOF) { retval = 1; - if (errcode > 0) { - update_ERRNO_saved(errcode); - if (do_traditional || ! has_endfile) - fatal(_("error reading input file `%s': %s"), - iop->name, strerror(errcode)); - } + if (*errcode > 0) + update_ERRNO_saved(*errcode); } else { NR += 1; FNR += 1; diff --git a/test/ChangeLog b/test/ChangeLog index 87b9cf12..334f1961 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,6 +1,7 @@ 2011-08-10 Arnold D. Robbins <arnold@skeeve.com> - * Makefile.am (fwtest3): New test. + * Makefile.am (beginfile2, fwtest3): New tests. + * beginfile2.awk, beginfile2.in, beginfile2.ok: New files. * fwtest3.awk, fwtest3.in, fwtest3.ok: New files. 2011-08-09 Arnold D. Robbins <arnold@skeeve.com> diff --git a/test/Makefile.am b/test/Makefile.am index 43b26599..a7789953 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -115,6 +115,9 @@ EXTRA_DIST = \ badargs.ok \ beginfile1.awk \ beginfile1.ok \ + beginfile2.in \ + beginfile2.ok \ + beginfile2.sh \ binmode1.ok \ childin.awk \ childin.in \ @@ -806,9 +809,11 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \ - backw badargs beginfile1 binmode1 clos1way delsub devfd devfd1 \ + backw badargs beginfile1 beginfile2 \ + binmode1 clos1way delsub devfd devfd1 \ devfd2 dumpvars exit fieldwdth fpat1 fpat2 fpatnull fsfwfs funlen \ - fwtest fwtest2 fwtest3 gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ + fwtest fwtest2 fwtest3 \ + gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers igncdym igncfs ignrcas2 ignrcase indirectcall lint \ lintold lintwarn manyfiles match1 match2 match3 mbstr1 nastyparm \ next nondec nondec2 patsplit posix printfbad1 printfbad2 procinfs \ @@ -1358,6 +1363,11 @@ beginfile1:: @AWKPATH=$(srcdir) $(AWK) -f $@.awk $(srcdir)/$@.awk . ./no/such/file Makefile >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +beginfile2: + @echo $@ + @-AWK="$(AWKPROG)" $(srcdir)/$@.sh $(srcdir)/$@.in > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + dumpvars:: @echo $@ @AWKPATH=$(srcdir) $(AWK) --dump-variables 1 < $(srcdir)/$@.in >/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Makefile.in b/test/Makefile.in index a31cd10b..1f1f5820 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -300,6 +300,9 @@ EXTRA_DIST = \ badargs.ok \ beginfile1.awk \ beginfile1.ok \ + beginfile2.in \ + beginfile2.ok \ + beginfile2.sh \ binmode1.ok \ childin.awk \ childin.in \ @@ -456,6 +459,9 @@ EXTRA_DIST = \ fwtest2.awk \ fwtest2.in \ fwtest2.ok \ + fwtest3.awk \ + fwtest3.in \ + fwtest3.ok \ gensub.awk \ gensub.in \ gensub.ok \ @@ -988,9 +994,11 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \ - backw badargs beginfile1 binmode1 clos1way delsub devfd devfd1 \ + backw badargs beginfile1 beginfile2 \ + binmode1 clos1way delsub devfd devfd1 \ devfd2 dumpvars exit fieldwdth fpat1 fpat2 fpatnull fsfwfs funlen \ - fwtest fwtest2 gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ + fwtest fwtest2 fwtest3 \ + gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers igncdym igncfs ignrcas2 ignrcase indirectcall lint \ lintold lintwarn manyfiles match1 match2 match3 mbstr1 nastyparm \ next nondec nondec2 patsplit posix printfbad1 printfbad2 procinfs \ @@ -1706,6 +1714,11 @@ beginfile1:: @AWKPATH=$(srcdir) $(AWK) -f $@.awk $(srcdir)/$@.awk . ./no/such/file Makefile >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +beginfile2: + @echo $@ + @-AWK="$(AWKPROG)" $(srcdir)/$@.sh $(srcdir)/$@.in > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + dumpvars:: @echo $@ @AWKPATH=$(srcdir) $(AWK) --dump-variables 1 < $(srcdir)/$@.in >/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2701,6 +2714,11 @@ fwtest2: @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +fwtest3: + @echo fwtest3 + @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + gensub: @echo gensub @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 0ea96731..cfbfc79e 100644 --- a/test/Maketests +++ b/test/Maketests @@ -955,6 +955,11 @@ fwtest2: @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +fwtest3: + @echo fwtest3 + @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + gensub: @echo gensub @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/beginfile2.in b/test/beginfile2.in new file mode 100644 index 00000000..5b7cc833 --- /dev/null +++ b/test/beginfile2.in @@ -0,0 +1,242 @@ +#TEST1# +BEGINFILE { + print "In BEGINFILE:", FILENAME +} +BEGIN { + count = 0 + print "In BEGIN" + while (getline > 0) + count++; + print count == NR +} + +#TEST2# +BEGINFILE { + print "In BEGINFILE:", FILENAME + nextfile +} +ENDFILE{ + print "In ENDFILE:", FILENAME +} + + +#TEST3# +BEGINFILE { + print "In BEGINFILE:", FILENAME +} +END { + print "executing END rule" + ARGV[ARGC++] = "beginfile.sh"; + count = 0 + while (getline> 0) + count++; + print count == FNR + print "Done executing END rule" +} +ENDFILE { + print "In ENDFILE:", FILENAME +} + +#TEST4# +BEGINFILE { + print "In BEGINFILE:", FILENAME + nextfile +} +END { + print "executing END rule" + ARGV[ARGC++] = "beginfile.sh"; + getline + print $0 + print "Done executing END rule" +} +ENDFILE { + print "ENDFILE:", FILENAME +} + + +#TEST5# +BEGIN { + getline + count++ + print NR, count +} +{ + count++ +} +END { + print NR == count +} + +#TEST6# +BEGINFILE { + print "In BEGINFILE:", FILENAME + count = 0 +} +BEGIN { + getline + count++ + print FNR, count +} +{ + count++ +} +ENDFILE { + print "In ENDFILE:", FILENAME + print count == FNR +} + +#TEST7# +BEGINFILE { + print "In BEGINFILE:", FILENAME + count = 0 + if (ARGIND == 1) + nextfile +} +BEGIN { + getline + print "In BEGIN:", FILENAME +} +{ count++ } +ENDFILE { + print "In ENDFILE:", FILENAME + print (FNR - count) +} + +#TEST8# +function f(a, b) { + getline + print FILENAME + print a, b +} +function g(x, y) { + return x +} +BEGINFILE { nextfile } +BEGIN { g(3, f(1, 2)) } + +#TEST9# +function f(a, b) { + b = b ":" a; + if (skip || ERRNO != "") { + print "Skipping:", b + nextfile + } + return b +} +BEGINFILE { print "In BEGINFILE:", f(FILENAME, ++i)} +FNR == 1 { print "In Rule:", FILENAME } +ENDFILE { print "In ENDFILE:", FILENAME } + +#TEST10# +function f() { + nextfile +} +function g( cnt) { + cnt = 0 + while (getline > 0) + cnt++; + return cnt +} +BEGINFILE { if (ARGIND == 1) f(); } +BEGIN { + print g(), NR +} + +#TEST11# +function f(a, b) { + print a + nextfile + print b +} +function g(x, y) { + print x + getline + return y +} +BEGINFILE { ARGIND == 1 ? g(3, f(FILENAME, 2)) : f(3, g(FILENAME, 2)) } + +#TEST12# +BEGINFILE { + print "In BEGINFILE:", FILENAME +} +function g() { + nextfile +} +function f( cnt) { + print cnt + 0 + while (getline > 0) { + if (++cnt == 2) { + g() + print "shouldn't see this line" + } + } +} +{ + print FNR + f() +} +ENDFILE { + print "In ENDFILE:", FILENAME +} + +#TEST13# +# exit in BEGINFILE +BEGINFILE { + print "In BEGINFILE:", FILENAME + exit(0) +} +ENDFILE { + print "In ENDFILE:", FILENAME +} +END { + print "In END:", FILENAME + while (getline > 0) + ; + print "shouldn't see this line" +} + +#TEST14# +# exit in ENDFILE +BEGINFILE { + print "In BEGINFILE:", FILENAME +} +ENDFILE { + print "In ENDFILE:", FILENAME + exit(0) +} +END { + print "In END:", FILENAME + while (getline > 0) + ; + print "shouldn't see this line" +} + +#TEST15# +BEGINFILE { + print "BEGINFILE:", FILENAME +} +{ nextfile } +END { + print NR +} + +#TEST16# +BEGINFILE { + print "In BEGINFILE:", FILENAME +} +BEGIN { + getline + print "In BEGIN:", FILENAME +} +{ + if (NR == FNR) { + print "In Rule:", FILENAME + nextfile + } + exit(0) +} + +ENDFILE { + print "In ENDFILE: ", FILENAME +} + diff --git a/test/beginfile2.ok b/test/beginfile2.ok new file mode 100644 index 00000000..c3029c7c --- /dev/null +++ b/test/beginfile2.ok @@ -0,0 +1,90 @@ +--Test 1a-- +In BEGIN +In BEGINFILE: beginfile2.in +1 +--Test 1b-- +In BEGIN +In BEGINFILE: beginfile2.in +In BEGINFILE: /file/does/not/exist +gawk: cmd. line:3: fatal: cannot open file `/file/does/not/exist' for reading (No such file or directory) +--Test 2-- +In BEGINFILE: beginfile2.in +In ENDFILE: beginfile2.in +In BEGINFILE: /file/does/not/exist +--Test 3-- +In BEGINFILE: beginfile2.in +In ENDFILE: beginfile2.in +executing END rule +In BEGINFILE: beginfile.sh +gawk: cmd. line:3: fatal: cannot open file `beginfile.sh' for reading (No such file or directory) +--Test 4-- +In BEGINFILE: beginfile2.in +ENDFILE: beginfile2.in +executing END rule +In BEGINFILE: beginfile.sh + +Done executing END rule +--Test 5-- +1 1 +1 +--Test 6-- +In BEGINFILE: beginfile2.in +1 1 +In ENDFILE: beginfile2.in +1 +--Test 7-- +In BEGINFILE: beginfile2.in +In ENDFILE: beginfile2.in +0 +In BEGINFILE: beginfile2.sh +In BEGIN: beginfile2.sh +In ENDFILE: beginfile2.sh +1 +--Test 8-- +beginfile2.in +1 2 +--Test 9a-- +Skipping: 1:/file/does/not/exist +In BEGINFILE: 2:beginfile2.in +In Rule: beginfile2.in +In ENDFILE: beginfile2.in +--Test 9b-- +Skipping: 1:/file/does/not/exist +Skipping: 2:beginfile2.in +In ENDFILE: beginfile2.in +--Test 10-- +82 82 +--Test 11-- +beginfile2.in +beginfile2.sh +gawk: cmd. line:9: fatal: non-redirected `getline' invalid inside `BEGINFILE' rule +--Test 12-- +In BEGINFILE: beginfile2.in +1 +0 +In ENDFILE: beginfile2.in +In BEGINFILE: beginfile2.sh +1 +0 +In ENDFILE: beginfile2.sh +--Test 13-- +In BEGINFILE: beginfile2.in +In END: beginfile2.in +In ENDFILE: beginfile2.in +In BEGINFILE: beginfile2.sh +--Test 14-- +In BEGINFILE: beginfile2.in +In ENDFILE: beginfile2.in +In END: beginfile2.in +In BEGINFILE: beginfile2.sh +In ENDFILE: beginfile2.sh +--Test 15-- +BEGINFILE: beginfile2.in +BEGINFILE: beginfile2.sh +2 +--Test 16-- +In BEGINFILE: beginfile2.in +In BEGIN: beginfile2.in +In Rule: beginfile2.in +In ENDFILE: beginfile2.in +In BEGINFILE: beginfile2.sh diff --git a/test/beginfile2.sh b/test/beginfile2.sh new file mode 100755 index 00000000..19deef62 --- /dev/null +++ b/test/beginfile2.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# beginfile2.sh --- test BEGINFILE/ENDFILE/getline/nextfile/exit combinations + +AWK="../gawk" +AWKPROG="beginfile2.in" +SCRIPT=`basename $0` + +if [ "$AWK" = "" ] +then + echo $0: You must set AWK >&2 + exit 1 +fi + +echo "--Test 1a--" +prog=$($AWK '/#TEST1#/, /#TEST2#/' $AWKPROG) +$AWK "$prog" $AWKPROG +echo "--Test 1b--" +$AWK "$prog" $AWKPROG /file/does/not/exist + +echo "--Test 2--" +prog=$($AWK '/#TEST2#/, /#TEST3#/' $AWKPROG) +$AWK "$prog" $AWKPROG /file/does/not/exist + +echo "--Test 3--" +prog=$($AWK '/#TEST3#/, /#TEST4#/' $AWKPROG) +$AWK "$prog" $AWKPROG + +echo "--Test 4--" +prog=$($AWK '/#TEST4#/, /#TEST5#/' $AWKPROG) +$AWK "$prog" $AWKPROG + +echo "--Test 5--" +prog=$($AWK '/#TEST5#/, /#TEST6#/' $AWKPROG) +$AWK "$prog" $AWKPROG + +echo "--Test 6--" +prog=$($AWK '/#TEST6#/, /#TEST7#/' $AWKPROG) +$AWK "$prog" $AWKPROG + +echo "--Test 7--" +prog=$($AWK '/#TEST7#/, /#TEST8#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 8--" +prog=$($AWK '/#TEST8#/, /#TEST9#/' $AWKPROG) +$AWK "$prog" $AWKPROG + +echo "--Test 9a--" +prog=$($AWK '/#TEST9#/, /#TEST10#/' $AWKPROG) +$AWK "$prog" /file/does/not/exist $AWKPROG +echo "--Test 9b--" +$AWK -vskip=1 "$prog" /file/does/not/exist $AWKPROG + +echo "--Test 10--" +prog=$($AWK '/#TEST10#/, /#TEST11#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 11--" +prog=$($AWK '/#TEST11#/, /#TEST12#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 12--" +prog=$($AWK '/#TEST12#/, /#TEST13#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 13--" +prog=$($AWK '/#TEST13#/, /#TEST14#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 14--" +prog=$($AWK '/#TEST14#/, /#TEST15#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 15--" +prog=$($AWK '/#TEST15#/, /#TEST16#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + +echo "--Test 16--" +prog=$($AWK '/#TEST16#/, /#TEST17#/' $AWKPROG) +$AWK "$prog" $AWKPROG $SCRIPT + |