gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, gawk-4.0-stable, updated. b8c993f5a867f3


From: Arnold Robbins
Subject: [gawk-diffs] [SCM] gawk branch, gawk-4.0-stable, updated. b8c993f5a867f38fa9edd343d7d90b4b36800be2
Date: Wed, 10 Aug 2011 19:36:41 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, gawk-4.0-stable has been updated
       via  b8c993f5a867f38fa9edd343d7d90b4b36800be2 (commit)
      from  0d1a4f152fa45eda08b5877e4989c3250beb280e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=b8c993f5a867f38fa9edd343d7d90b4b36800be2

commit b8c993f5a867f38fa9edd343d7d90b4b36800be2
Author: Arnold D. Robbins <address@hidden>
Date:   Wed Aug 10 22:36:00 2011 +0300

    BEGINFILE/ENDFILE code redone.

diff --git a/ChangeLog b/ChangeLog
index 684bb9d..3ac6378 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2011-08-10         John Haque      <address@hidden>
+
+       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     <address@hidden>
 
        Fix (apparently long-standing) problem with FIELDWIDTHS.
diff --git a/awk.h b/awk.h
index f3d3665..4b4210f 100644
--- a/awk.h
+++ b/awk.h
@@ -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);
diff --git a/awkgram.c b/awkgram.c
index 6471150..a4d9f5d 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -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 */
        }
 
diff --git a/awkgram.y b/awkgram.y
index fb917c2..6d3f1f7 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -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 */
        }
 
diff --git a/debug.c b/debug.c
index 4cda95c..29ce8b1 100644
--- a/debug.c
+++ b/debug.c
@@ -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 e344c40..70fb686 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 87d8ff2..9dbd45c 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,
address@hidden 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.
address@hidden/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
address@hidden 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
diff --git a/eval.c b/eval.c
index ea45efd..0a4a738 100644
--- a/eval.c
+++ b/eval.c
@@ -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)
diff --git a/io.c b/io.c
index c062610..1dcf217 100644
--- a/io.c
+++ b/io.c
@@ -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 87b9cf1..334f196 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,6 +1,7 @@
 2011-08-10         Arnold D. Robbins     <address@hidden>
 
-       * 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     <address@hidden>
diff --git a/test/Makefile.am b/test/Makefile.am
index 43b2659..a778995 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 address@hidden $(srcdir)/address@hidden . 
./no/such/file Makefile  >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
+beginfile2:
+       @echo $@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden $(srcdir)/address@hidden > 
_$@ 2>&1
+       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
 dumpvars::
        @echo $@
        @AWKPATH=$(srcdir) $(AWK) --dump-variables 1 < $(srcdir)/address@hidden 
>/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/Makefile.in b/test/Makefile.in
index a31cd10..1f1f582 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 address@hidden $(srcdir)/address@hidden . 
./no/such/file Makefile  >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
+beginfile2:
+       @echo $@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden $(srcdir)/address@hidden > 
_$@ 2>&1
+       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
 dumpvars::
        @echo $@
        @AWKPATH=$(srcdir) $(AWK) --dump-variables 1 < $(srcdir)/address@hidden 
>/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2701,6 +2714,11 @@ fwtest2:
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
+fwtest3:
+       @echo fwtest3
+       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
 gensub:
        @echo gensub
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/Maketests b/test/Maketests
index 0ea9673..cfbfc79 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -955,6 +955,11 @@ fwtest2:
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
+fwtest3:
+       @echo fwtest3
+       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
 gensub:
        @echo gensub
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/beginfile2.in b/test/beginfile2.in
new file mode 100644
index 0000000..5b7cc83
--- /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 0000000..c3029c7
--- /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 0000000..19deef6
--- /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
+

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog          |   28 +++
 awk.h              |   25 ++-
 awkgram.c          |   11 +-
 awkgram.y          |   11 +-
 debug.c            |   23 ++-
 doc/gawk.info      |  496 ++++++++++++++++++++++++++--------------------------
 doc/gawk.texi      |   12 +-
 eval.c             |  378 +++++++++++++++++++++++++++-------------
 io.c               |   25 +--
 test/ChangeLog     |    3 +-
 test/Makefile.am   |   14 ++-
 test/Makefile.in   |   22 ++-
 test/Maketests     |    5 +
 test/beginfile2.in |  242 +++++++++++++++++++++++++
 test/beginfile2.ok |   90 ++++++++++
 test/beginfile2.sh |   82 +++++++++
 16 files changed, 1050 insertions(+), 417 deletions(-)
 create mode 100644 test/beginfile2.in
 create mode 100644 test/beginfile2.ok
 create mode 100755 test/beginfile2.sh


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]