diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2015-03-31 22:35:15 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2015-03-31 22:35:15 +0300 |
commit | bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513 (patch) | |
tree | 95f926cd9bf02578e9c860726a56441ac00e95b2 | |
parent | eb53fb0398911202d4361b869eefa6c1449ebec8 (diff) | |
parent | 902b25a40d5cc612dd7a0becb27a5a48afa49716 (diff) | |
download | egawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.tar.gz egawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.tar.bz2 egawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.zip |
Merge branch 'master' into feature/regex-type
-rw-r--r-- | ChangeLog | 228 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | awk.h | 9 | ||||
-rw-r--r-- | awkgram.c | 24 | ||||
-rw-r--r-- | awkgram.y | 24 | ||||
-rw-r--r-- | builtin.c | 140 | ||||
-rw-r--r-- | configh.in | 6 | ||||
-rwxr-xr-x | configure | 5 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | doc/ChangeLog | 37 | ||||
-rw-r--r-- | doc/gawk.1 | 47 | ||||
-rw-r--r-- | doc/gawk.info | 1395 | ||||
-rw-r--r-- | doc/gawk.texi | 189 | ||||
-rw-r--r-- | doc/gawktexi.in | 189 | ||||
-rw-r--r-- | eval.c | 6 | ||||
-rw-r--r-- | extension/ChangeLog | 174 | ||||
-rw-r--r-- | extension/testext.c | 205 | ||||
-rw-r--r-- | gawkapi.c | 105 | ||||
-rw-r--r-- | gawkapi.h | 40 | ||||
-rw-r--r-- | interpret.h | 29 | ||||
-rw-r--r-- | io.c | 169 | ||||
-rw-r--r-- | test/ChangeLog | 54 | ||||
-rw-r--r-- | test/Makefile.am | 32 | ||||
-rw-r--r-- | test/Makefile.in | 47 | ||||
-rw-r--r-- | test/Maketests | 15 | ||||
-rw-r--r-- | test/errno.awk | 10 | ||||
-rw-r--r-- | test/errno.in | 3 | ||||
-rw-r--r-- | test/errno.ok | 3 | ||||
-rw-r--r-- | test/exitval3.awk | 2 | ||||
-rw-r--r-- | test/exitval3.ok | 1 | ||||
-rw-r--r-- | test/getfile.awk | 35 | ||||
-rw-r--r-- | test/getfile.ok | 17 | ||||
-rw-r--r-- | test/id.ok | 1 | ||||
-rw-r--r-- | test/indirectbuiltin.awk | 371 | ||||
-rw-r--r-- | test/indirectbuiltin.ok | 43 | ||||
-rw-r--r-- | test/testext.ok | 12 | ||||
-rw-r--r-- | test/timeout.awk | 26 | ||||
-rw-r--r-- | test/timeout.ok | 12 |
38 files changed, 2998 insertions, 718 deletions
@@ -1,3 +1,54 @@ +2015-03-31 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (call_sub): Renamed from call_sub_func. + (call_match, call_split_func): Declare. + * builtin.c (call_sub): Renamed from call_sub_func. + (call_match, call_split_func): New functions. + * interpret.h (r_interpret): Call new functions as appropriate. + * node.c (r_unref): Revert change to handle Node_regex, not needed. + +2015-03-31 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (r_get_field): Declare. + * builtin.c (call_sub_func): Rearrange the stack to be what + the buitin function expects. + * eval.c (r_get_field): Make extern. + +2015-03-27 Arnold D. Robbins <arnold@skeeve.com> + + * io.c (redirect): Change not_string from int to bool. + * gawkapi.c (api_get_file): Minor stylistic improvements. + * NEWS: Updated for retryable I/O and new API function. + +2015-03-24 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (make_regnode): Make extern. + * awk.h (make_regnode): Declare. + * builtin.c (call_sub_func): Start on reworking the stack to + be what do_sub() expects. Still needs work. + * interpret.h (r_interpret): Add a cast in comparison with do_sub(). + * node.c (r_unref): Handle Node_regex nodes. + +2015-03-24 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * interpret.h (r_interpret): When Op_K_exit has an argument of + Nnull_string, do not update exit_val, since no value was supplied. + +2015-03-24 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h, gawkapi.c, io.c: Minor code reformatting. + +2015-03-20 Arnold D. Robbins <arnold@skeeve.com> + + Start on fixing indirect calls of builtins. + + * awk.h (call_sub_func): Add declaration. + * awkgram.y (lookup_builtin): Handle length, sub functions. + (install_builtin): Handle length function. + * builtin.c (call_sub_func): New function. + * interpret.h (r_interpret): If calling do_sub, do it through + call_sub_func(). + 2015-03-19 Arnold D. Robbins <arnold@skeeve.com> * re.c (re_update): Handle hard regex - for sub/gsub/gensub. @@ -206,6 +257,22 @@ * builtin.c (do_length): Update comment. * main.c (init_vars): Just call load_procinfo() and `load_environ()'. +2015-01-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Revert changes to API deferred variable creation -- these variables + should be created when lookup is called, not when update is called. + * awk.h (variable_create): Remove function declaration. + * awkgram.y (variable_create): Remove function. + (variable): Restore variable_create functionality inline. + * gawkapi.c (api_sym_update): Revert to using install_symbol, since the + deferred variable check should be done when lookup is called, not here. + +2015-01-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.c (api_set_array_element): Remove stray call to + make_aname. I cannot see what purpose this served. Maybe I am + missing something. + 2015-01-07 Arnold D. Robbins <arnold@skeeve.com> * configure.ac: Update debug flags if developing. @@ -224,6 +291,59 @@ (do_add_scrfile): Set it on -l. (process_deferred): Check it also. +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.c (api_sym_update): If copying a subarray, must update + the parent_array pointer. Also, call the astore hook if non-NULL. + (api_set_array_element): Call the astore hook if non-NULL. + +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (variable_create): Now takes a 3rd argument to tell caller + whether this is a deferred variable. + * awkgram.y (variable_create): Return indicator of whether this is + a deferred variable in a newly added 3rd arg. + (variable): Pass 3rd arg to variable_create. + * gawkapi.c (api_sym_update): If we triggered the creation of a deferred + variable, we must merge the extension's array elements into the deffered + array, not the other way around. The ENVIRON array has special funcs + to call setenv and unsetenv. + +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (variable_create): Declare new function. + * awkgram.y (variable_create): New function to create a variable + taking the deferred variable list into consideration. + (variable): Call new function variable_create if the variable is + not found. + * gawkapi.c (api_sym_update): If an array is being created, then + call new function variable_create instead of install_symbol. If this + is the first reference to a deferred variable, than the new array + may contain elements that must be merged into the array provided by + the extension. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * io.c (wait_any): If the `interesting' argument is non-zero, then we + must not return until that child process has exited, since the caller + gawk_pclose depends on our returning its exit status. So in that case, + do not pass WNOHANG to waitpid. + +2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h: Fix another comment typo. + +2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h: Fix typo in comment. + +2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h (gawk_api): Modify api_get_file to remove the typelen + argument. + (get_file): Remove typelen argument from the macro. + * gawkapi.c (api_get_file): Remove typelen argument. + 2014-12-24 Arnold D. Robbins <arnold@skeeve.com> * profile.c (pprint): Be sure to set ip2 in all paths @@ -366,6 +486,36 @@ and a it's a Node_val set to Nnull_string, return AWK_UNDEFINED instead of AWK_NUMBER 0. +2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (redirect_string): First argument should be const. Add a new + extfd argument to enable extensions to create files with pre-opened + file descriptors. + (after_beginfile): Declare function used in both eval.c and gawkapi.c. + * eval.c (after_beginfile): Remove extern declaration now in awk.h. + * gawkapi.c (api_get_file): Implement API changes to return + awk_input_buf_t and/or awk_output_buf_t info, as well as accept an + fd for inserting an opened file into the table. + * gawkapi.h (gawk_api): Modify the api_get_file declaration to + return awk_bool_t and add 3 new arguments -- a file descriptor + for inserting an already opened file, and awk_input_buf_t and + awk_output_buf_t to return info about both input and output. + (get_file): Add new arguments to the macro. + * io.c (redirect_string): First arg should be const, and add a new + extfd arg so extensions can pass in a file that has already been + opened by the extension. Use the passed-in fd when appropriate, + and pass it into two_way_open. + (redirect): Pass new fd -1 arg to redirect_string. + (two_way_open): Accept new extension fd parameter and open it + as a socket. + +2014-11-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * io.c (retryable): New function to indicate whether I/O can be + retried for this file instead of throwing a hard error. + (get_a_record) Check whether this file is configured for retryable + I/O before returning nonstandard -2. + 2014-11-03 Norihiro Tanaka <noritnk@kcn.ne.jp> * re.c (research): Use dfa superset to improve matching speed. @@ -1534,6 +1684,45 @@ * io.c (get_a_record): Change `min' to `MIN' for consistency with other files and general practice. +2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * configure.ac (AC_CHECK_FUNCS): Check for sigprocmask. + * io.c (wait_any): If sigprocmask is available, block signals instead + of ignoring them temporarily. + +2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h (gawk_api): Document that the api_get_file function will not + access the file type and length arguments if the file name is empty. + +2013-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * configure.ac (AC_CHECK_FUNCS): Add a check for waitpid. + * io.c (wait_any): Enhance comment to explain why we loop reaping all + exited children when the argument is zero. When available, use waitpid + with WNOHANG to avoid blocking. Remove my previous incorrect patch to + exit after reaping the first child. The function is intended to + wait for all children, since we are not careful about reaping children + as soon as they die. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h (gawk_api): Remove unused api_lookup_file hook. + (lookup_file): Remove associated macro. + * gawkapi.c (api_lookup_file): Remove unused function. + (api_impl): Remove unused api_lookup_file hook. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awkgram.y (main_beginfile): Declare new global INSTRUCTION *. + (parse_program): Set main_beginfile to point to the BEGINFILE + instruction block. + * gawkapi.c (api_get_file): After nextfile starts a new file, + we need to run the BEGINFILE actions. We retrieve the + instruction pointer from main_beginfile and execute it until + we reach the Op_after_beginfile opcode. We then run after_beginfile + manually and restore the value of currule and source. + 2013-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawkapi.h (awk_element_t): Add comment indicating that the array @@ -1544,6 +1733,45 @@ force_string redundant, since node_to_awk_value does that internally when we request a string. +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * eval.c (update_ERRNO_string): Set PROCINFO["errno"] to 0. + * io.c (inrec): Since get_a_record may now return -2, be sure + to throw an error in that case as well. + (wait_any): Fix what appears to be a bug. The old logic repeatedly + called wait until it failed. When a process has multiple children, + this causes it to stall until all of them have exited. Instead, + we now exit the function after the first successful wait call. + (do_getline_redir, do_getline): Handle case where get_a_record + returns -2. + (errno_io_retry): New function to decide whether an I/O operation should + be retried. + (get_a_record): When read returns an error, call errno_io_retry to + decide whether the operation should be retried. If so, return -2 + instead of setting the IOP_AT_EOF flag. + +2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * eval.c (update_ERRNO_int, unset_ERRNO): Update PROCINFO["errno"]. + +2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (redirect_string): Declare new function that provides API access + to the redirection mechanism. + * gawkapi.h (GAWK_API_MINOR_VERSION): Bump from 0 to 1 since 2 new + hooks were added to the api. + (gawk_api_t): Add 2 new functions api_lookup_file and api_get_file. + (lookup_file, get_file): New macros to wrap the new API functions. + * gawkapi.c (curfile): Declare this extern, since it is needed + by lookup_file and get_flie. + (api_lookup_file): Find an open file using curfile or getredirect(). + (api_get_file): Find or open a file using curfile or redirect_string(). + (api_impl): Add api_lookup_file and api_get_file. + * io.c (redirect_string): Renamed from redirect and changed arguments + to take a string instead of a 'NODE *'. This allows it to be called + through the API's new get_file hook. + (redirect): Now implemented by calling redirect_string backend function. + 2013-07-04 Arnold D. Robbins <arnold@skeeve.com> * builtin.c (format_tree): Fixes for %c with multibyte characters @@ -45,6 +45,12 @@ Changes from 4.1.x to 4.2.0 system, these files belong in /etc/profile.d, but the appropriate location may be different on other platforms. +11. Gawk now supports retryable I/O via PROCINFO[input-file, "RETRY"]; see + the manual. + +12. The API minor version has been increased to two; the get_file() + API provides access to open redirections. Also see the manual. + Changes from 4.1.1 to 4.1.2 --------------------------- @@ -1339,6 +1339,7 @@ extern void install_builtins(void); extern bool is_alpha(int c); extern bool is_alnum(int c); extern bool is_identchar(int c); +extern NODE *make_regnode(int type, NODE *exp); /* builtin.c */ extern double double_to_int(double d); extern NODE *do_exp(int nargs); @@ -1368,6 +1369,9 @@ extern NODE *do_rand(int nargs); extern NODE *do_srand(int nargs); extern NODE *do_match(int nargs); extern NODE *do_sub(int nargs, unsigned int flags); +extern NODE *call_sub(const char *name, int nargs); +extern NODE *call_match(int nargs); +extern NODE *call_split_func(const char *name, int nargs); extern NODE *format_tree(const char *, size_t, NODE **, long); extern NODE *do_lshift(int nargs); extern NODE *do_rshift(int nargs); @@ -1416,6 +1420,7 @@ extern NODE **r_get_lhs(NODE *n, bool reference); extern STACK_ITEM *grow_stack(void); extern void dump_fcall_stack(FILE *fp); extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth); +extern NODE **r_get_field(NODE *n, Func_ptr *assign, bool reference); /* ext.c */ extern NODE *do_ext(int nargs); void load_ext(const char *lib_name); /* temporary */ @@ -1485,6 +1490,9 @@ extern void set_FNR(void); extern void set_NR(void); extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal); +extern struct redirect *redirect_string(const char *redir_exp_str, + size_t redir_exp_len, bool not_string_flag, int redirtype, + int *errflg, int extfd, bool failure_fatal); extern NODE *do_close(int nargs); extern int flush_io(void); extern int close_io(bool *stdio_problem); @@ -1505,6 +1513,7 @@ extern int is_off_limits_var(const char *var); extern char *estrdup(const char *str, size_t len); extern void update_global_values(); extern long getenv_long(const char *name); +extern void after_beginfile(IOBUF **curfile); /* mpfr.c */ extern void set_PREC(void); @@ -113,7 +113,6 @@ static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op); static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype); -static NODE *make_regnode(int type, NODE *exp); static int count_expressions(INSTRUCTION **list, bool isarg); static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); static void add_lint(INSTRUCTION *list, LINTTYPE linttype); @@ -184,6 +183,7 @@ static INSTRUCTION *ip_atexit = NULL; static INSTRUCTION *ip_end; static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; +INSTRUCTION *main_beginfile; static INSTRUCTION *comment = NULL; static INSTRUCTION *program_comment = NULL; @@ -4897,7 +4897,7 @@ parse_program(INSTRUCTION **pcode) ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; else { ip_endfile = instruction(Op_no_op); - ip_beginfile = instruction(Op_no_op); + main_beginfile = ip_beginfile = instruction(Op_no_op); 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; @@ -7237,7 +7237,7 @@ variable(int location, char *name, NODETYPE type) /* make_regnode --- make a regular expression node */ -static NODE * +NODE * make_regnode(int type, NODE *exp) { NODE *n; @@ -8395,13 +8395,26 @@ lookup_builtin(const char *name) { int mid = check_special(name); - if (mid == -1 || tokentab[mid].class != LEX_BUILTIN) + if (mid == -1) return NULL; + + switch (tokentab[mid].class) { + case LEX_BUILTIN: + case LEX_LENGTH: + break; + default: + return NULL; + } + #ifdef HAVE_MPFR if (do_mpfr) return tokentab[mid].ptr2; #endif + /* And another special case... */ + if (tokentab[mid].value == Op_sub_builtin) + return (builtin_func_t) do_sub; + return tokentab[mid].ptr; } @@ -8414,7 +8427,8 @@ install_builtins(void) j = sizeof(tokentab) / sizeof(tokentab[0]); for (i = 0; i < j; i++) { - if ( tokentab[i].class == LEX_BUILTIN + if ( (tokentab[i].class == LEX_BUILTIN + || tokentab[i].class == LEX_LENGTH) && (tokentab[i].flags & DEBUG_USE) == 0) { (void) install_symbol(tokentab[i].operator, Node_builtin_func); } @@ -73,7 +73,6 @@ static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op); static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype); -static NODE *make_regnode(int type, NODE *exp); static int count_expressions(INSTRUCTION **list, bool isarg); static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); static void add_lint(INSTRUCTION *list, LINTTYPE linttype); @@ -144,6 +143,7 @@ static INSTRUCTION *ip_atexit = NULL; static INSTRUCTION *ip_end; static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; +INSTRUCTION *main_beginfile; static INSTRUCTION *comment = NULL; static INSTRUCTION *program_comment = NULL; @@ -2485,7 +2485,7 @@ parse_program(INSTRUCTION **pcode) ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; else { ip_endfile = instruction(Op_no_op); - ip_beginfile = instruction(Op_no_op); + main_beginfile = ip_beginfile = instruction(Op_no_op); 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; @@ -4825,7 +4825,7 @@ variable(int location, char *name, NODETYPE type) /* make_regnode --- make a regular expression node */ -static NODE * +NODE * make_regnode(int type, NODE *exp) { NODE *n; @@ -5983,13 +5983,26 @@ lookup_builtin(const char *name) { int mid = check_special(name); - if (mid == -1 || tokentab[mid].class != LEX_BUILTIN) + if (mid == -1) return NULL; + + switch (tokentab[mid].class) { + case LEX_BUILTIN: + case LEX_LENGTH: + break; + default: + return NULL; + } + #ifdef HAVE_MPFR if (do_mpfr) return tokentab[mid].ptr2; #endif + /* And another special case... */ + if (tokentab[mid].value == Op_sub_builtin) + return (builtin_func_t) do_sub; + return tokentab[mid].ptr; } @@ -6002,7 +6015,8 @@ install_builtins(void) j = sizeof(tokentab) / sizeof(tokentab[0]); for (i = 0; i < j; i++) { - if ( tokentab[i].class == LEX_BUILTIN + if ( (tokentab[i].class == LEX_BUILTIN + || tokentab[i].class == LEX_LENGTH) && (tokentab[i].flags & DEBUG_USE) == 0) { (void) install_symbol(tokentab[i].operator, Node_builtin_func); } @@ -3072,6 +3072,146 @@ done: return make_number((AWKNUM) matches); } +/* call_sub --- call do_sub indirectly */ + +NODE * +call_sub(const char *name, int nargs) +{ + unsigned int flags = 0; + NODE *regex, *replace, *glob_flag; + NODE **lhs, *rhs; + NODE *zero = make_number(0.0); + NODE *result; + + if (name[0] == 'g') { + if (name[1] == 'e') + flags = GENSUB; + else + flags = GSUB; + } + + if (flags == 0 || flags == GSUB) { + /* sub or gsub */ + if (nargs != 2) + fatal(_("%s: can be called indirectly only with two arguments"), name); + + replace = POP_STRING(); + regex = POP(); /* the regex */ + /* + * push regex + * push replace + * push $0 + */ + regex = make_regnode(Node_regex, regex); + PUSH(regex); + PUSH(replace); + lhs = r_get_field(zero, (Func_ptr *) 0, true); + nargs++; + PUSH_ADDRESS(lhs); + } else { + /* gensub */ + if (nargs == 4) + rhs = POP(); + else + rhs = NULL; + glob_flag = POP_STRING(); + replace = POP_STRING(); + regex = POP(); /* the regex */ + /* + * push regex + * push replace + * push glob_flag + * if (nargs = 3) { + * push $0 + * nargs++ + * } + */ + regex = make_regnode(Node_regex, regex); + PUSH(regex); + PUSH(replace); + PUSH(glob_flag); + if (rhs == NULL) { + lhs = r_get_field(zero, (Func_ptr *) 0, true); + rhs = *lhs; + UPREF(rhs); + PUSH(rhs); + nargs++; + } + PUSH(rhs); + } + + + unref(zero); + result = do_sub(nargs, flags); + if (flags != GENSUB) + reset_record(); + return result; +} + +/* call_match --- call do_match indirectly */ + +NODE * +call_match(int nargs) +{ + NODE *regex, *text, *array; + NODE *result; + + regex = text = array = NULL; + if (nargs == 3) + array = POP(); + regex = POP(); + + /* Don't need to pop the string just to push it back ... */ + + regex = make_regnode(Node_regex, regex); + PUSH(regex); + + if (array) + PUSH(array); + + result = do_match(nargs); + return result; +} + +/* call_split_func --- call do_split or do_pat_split indirectly */ + +NODE * +call_split_func(const char *name, int nargs) +{ + NODE *regex, *seps; + NODE *result; + + regex = seps = NULL; + if (nargs < 2) + fatal(_("indirect call to %s requires at least two arguments"), + name); + + if (nargs == 4) + seps = POP(); + + if (nargs >= 3) { + regex = POP_STRING(); + regex = make_regnode(Node_regex, regex); + } else { + if (name[0] == 's') { + regex = make_regnode(Node_regex, FS_node->var_value); + regex->re_flags |= FS_DFLT; + } else + regex = make_regnode(Node_regex, FPAT_node->var_value); + nargs++; + } + + /* Don't need to pop the string or the data array */ + + PUSH(regex); + + if (seps) + PUSH(seps); + + result = (name[0] == 's') ? do_split(nargs) : do_patsplit(nargs); + + return result; +} /* make_integer - Convert an integer to a number node. */ @@ -168,6 +168,9 @@ /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID +/* Define to 1 if you have the `sigprocmask' function. */ +#undef HAVE_SIGPROCMASK + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF @@ -293,6 +296,9 @@ /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP +/* Define to 1 if you have the `waitpid' function. */ +#undef HAVE_WAITPID + /* Define to 1 if you have the <wchar.h> header file. */ #undef HAVE_WCHAR_H @@ -10323,9 +10323,10 @@ esac for ac_func in atexit btowc fmod getgrent getgroups grantpt \ isascii iswctype iswlower iswupper mbrlen \ memcmp memcpy memcpy_ulong memmove memset \ - memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \ + memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \ + snprintf strchr \ strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ - system tmpfile towlower towupper tzset usleep wcrtomb \ + system tmpfile towlower towupper tzset usleep waitpid wcrtomb \ wcscoll wctype do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` diff --git a/configure.ac b/configure.ac index 7c922ccf..a6972ab2 100644 --- a/configure.ac +++ b/configure.ac @@ -269,9 +269,10 @@ esac AC_CHECK_FUNCS(atexit btowc fmod getgrent getgroups grantpt \ isascii iswctype iswlower iswupper mbrlen \ memcmp memcpy memcpy_ulong memmove memset \ - memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \ + memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \ + snprintf strchr \ strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ - system tmpfile towlower towupper tzset usleep wcrtomb \ + system tmpfile towlower towupper tzset usleep waitpid wcrtomb \ wcscoll wctype) dnl this check is for both mbrtowc and the mbstate_t type, which is good AC_FUNC_MBRTOWC diff --git a/doc/ChangeLog b/doc/ChangeLog index 92e95a0b..e41bf158 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,21 @@ +2015-03-31 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Update discussion of calling built-in functions + indirectly. Small additional fix relating to rand(). Thanks + to Antonio Colombo. + +2015-03-27 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Minor edits. + +2015-03-24 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Minor fixes from Antonio Colombo and new exercise + in chapter 16. + * gawk.1: Minor edits. + * gawktexi.in: Edits in material on errno and retryable and get_file + API. + 2015-03-17 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawktexi.in: Modify inplace.awk to call inplace_end in BEGINFILE @@ -138,6 +156,25 @@ * gawktexi.in: Add info that nonfatal I/O works with stdout and stderr. Revise version info and what was added when. +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in: Improve get_file documentation. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in: Replace "Retrying I/O" with "Retrying Input", since this + feature pertains to input, not output. + +2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in: Document the get_file API function. + +2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawk.1: Document new features PROCINFO["errno"] and + PROCINFO["input", "RETRY"], and new getline return value of -2. + * gawktexi.in: Ditto. + 2014-12-26 Antonio Giovanni Colombo <azc100@gmail.com> * gawktexi.in (Glossary): Really sort the items. @@ -13,7 +13,7 @@ . if \w'\(rq' .ds rq "\(rq . \} .\} -.TH GAWK 1 "Aug 03 2014" "Free Software Foundation" "Utility Commands" +.TH GAWK 1 "Mar 24 2015" "Free Software Foundation" "Utility Commands" .SH NAME gawk \- pattern scanning and processing language .SH SYNOPSIS @@ -942,6 +942,15 @@ then will contain a string describing the error. The value is subject to translation in non-English locales. +If the string in +.B ERRNO +corresponds to a system error in the +.IR errno (3) +variable, then the numeric value can be found in +.B PROCINFO["errno"]. +For non-system errors, +.B PROCINFO["errno"] +will be zero. .TP .B FIELDWIDTHS A whitespace separated list of field widths. When set, @@ -1103,6 +1112,13 @@ system call. The default time format string for .BR strftime() . .TP +\fBPROCINFO["errno"]\fP +The value of +.IR errno (3) +when +.BR ERRNO +is set to the associated error message. +.TP \fBPROCINFO["euid"]\fP The value of the .IR geteuid (2) @@ -1221,6 +1237,28 @@ where is a redirection string or a filename. A value of zero or less than zero means no timeout. .TP +\fBPROCINFO["input", "RETRY"]\fP +If an I/O error that may be retried occurs when reading data from +.IR input , +and this array entry exists, then +.B getline +will return \-2 instead of following the default behavior of returning \-1 +and configuring +.IR input +to return no further data. +An I/O error that may be retried is one where +.IR errno (3) +has the value +.IR EAGAIN , +.IR EWOULDBLOCK , +.IR EINTR , +or +.IR ETIMEDOUT . +This may be useful in conjunction with +\fBPROCINFO["input", "READ_TIMEOUT"]\fP +or situations where a file descriptor has been configured to behave in a +non-blocking fashion. +.TP \fBPROCINFO["mpfr_version"]\fP The version of the GNU MPFR library used for arbitrary precision number support in @@ -2289,6 +2327,13 @@ below.) The .B getline command returns 1 on success, 0 on end of file, and \-1 on an error. +If the +.IR errno (3) +value indicates that the I/O operation may be retried, +and \fBPROCINFO["input", "RETRY"]\fP +is set, then \-2 will be returned instead of \-1, and further calls to +.B getline +may be attempted. Upon an error, .B ERRNO is set to a string describing the problem. diff --git a/doc/gawk.info b/doc/gawk.info index 3e12596d..24a4a638 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -217,6 +217,7 @@ entitled "GNU Free Documentation License". `getline'. * Getline Summary:: Summary of `getline' Variants. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -558,6 +559,7 @@ entitled "GNU Free Documentation License". * Array Functions:: Functions for working with arrays. * Flattening Arrays:: How to flatten arrays. * Creating Arrays:: How to create and populate arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension Versioning:: API Version information. * Extension API Informational Variables:: Variables providing information about @@ -4178,6 +4180,7 @@ have to be named on the `awk' command line (*note Getline::). * Getline:: Reading files under explicit program control using the `getline' function. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -5450,6 +5453,11 @@ record, such as a file that cannot be opened, then `getline' returns -1. In this case, `gawk' sets the variable `ERRNO' to a string describing the error that occurred. + If `ERRNO' indicates that the I/O operation may be retried, and +`PROCINFO["INPUT", "RETRY"]' is set, then `getline' returns -2 instead +of -1, and further calls to `getline' may be attemped. *Note Retrying +Input::, for further information about this feature. + In the following examples, COMMAND stands for a string value that represents a shell command. @@ -5886,7 +5894,7 @@ VAR Table 4.1: `getline' variants and what they set -File: gawk.info, Node: Read Timeout, Next: Command-line directories, Prev: Getline, Up: Reading Files +File: gawk.info, Node: Read Timeout, Next: Retrying Input, Prev: Getline, Up: Reading Files 4.10 Reading Input with a Timeout ================================= @@ -5965,7 +5973,8 @@ a per-command or per-connection basis. `gawk' considers a timeout event to be an error even though the attempt to read from the underlying device may succeed in a later attempt. This is a limitation, and it also means that you cannot use -this to multiplex input from two or more sources. +this to multiplex input from two or more sources. *Note Retrying +Input::, for a way to enable later I/O attempts to succeed. Assigning a timeout value prevents read operations from blocking indefinitely. But bear in mind that there are other ways `gawk' can @@ -5980,9 +5989,36 @@ writing. (1) This assumes that standard input is the keyboard. -File: gawk.info, Node: Command-line directories, Next: Input Summary, Prev: Read Timeout, Up: Reading Files +File: gawk.info, Node: Retrying Input, Next: Command-line directories, Prev: Read Timeout, Up: Reading Files + +4.11 Retrying Reads After Certain Input Errors +============================================== + +This minor node describes a feature that is specific to `gawk'. + + When `gawk' encounters an error while reading input, by default +`getline' returns -1, and subsequent attempts to read from that file +result in an end-of-file indication. However, you may optionally +instruct `gawk' to allow I/O to be retried when certain errors are +encountered by setting a special element in the `PROCINFO' array (*note +Auto-set::): + + PROCINFO["INPUT_NAME", "RETRY"] = 1 + + When this element exists, `gawk' checks the value of the system (C +language) `errno' variable when an I/O error occurs. If `errno' +indicates a subsequent I/O attempt may succeed, `getline' instead +returns -2 and further calls to `getline' may succeed. This applies to +the `errno' values `EAGAIN', `EWOULDBLOCK', `EINTR', or `ETIMEDOUT'. + + This feature is useful in conjunction with `PROCINFO["INPUT_NAME", +"READ_TIMEOUT"]' or situations where a file descriptor has been +configured to behave in a non-blocking fashion. + + +File: gawk.info, Node: Command-line directories, Next: Input Summary, Prev: Retrying Input, Up: Reading Files -4.11 Directories on the Command Line +4.12 Directories on the Command Line ==================================== According to the POSIX standard, files named on the `awk' command line @@ -6005,7 +6041,7 @@ usable data from an `awk' program. File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-line directories, Up: Reading Files -4.12 Summary +4.13 Summary ============ * Input is split into records based on the value of `RS'. The @@ -6079,7 +6115,7 @@ File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-li File: gawk.info, Node: Input Exercises, Prev: Input Summary, Up: Reading Files -4.13 Exercises +4.14 Exercises ============== 1. Using the `FIELDWIDTHS' variable (*note Constant Size::), write a @@ -10440,6 +10476,11 @@ Options::), they are not special: `getline' returning -1. You are, of course, free to clear it yourself before doing an I/O operation. + If the value of `ERRNO' corresponds to a system error in the C + `errno' variable, then `PROCINFO["errno"]' will be set to the value + of `errno'. For non-system errors, `PROCINFO["errno"]' will be + zero. + `FILENAME' The name of the current input file. When no data files are listed on the command line, `awk' reads from the standard input and @@ -10488,6 +10529,10 @@ Options::), they are not special: `PROCINFO["egid"]' The value of the `getegid()' system call. + `PROCINFO["errno"]' + The value of the C `errno' variable when `ERRNO' is set to + the associated error message. + `PROCINFO["euid"]' The value of the `geteuid()' system call. @@ -10598,6 +10643,10 @@ Options::), they are not special: open input file, pipe, or coprocess. *Note Read Timeout::, for more information. + * It may be used to indicate that input may be retried when it + fails due to certain errors. *Note Retrying Input::, for + more information. + * It may be used to cause coprocesses to communicate over pseudo-ttys instead of through two-way pipes; this is discussed further in *note Two-way I/O::. @@ -12026,9 +12075,9 @@ brackets ([ ]): return int(n * rand()) } - The multiplication produces a random number greater than zero and - less than `n'. Using `int()', this result is made into an integer - between zero and `n' - 1, inclusive. + The multiplication produces a random number greater than or equal + to zero and less than `n'. Using `int()', this result is made into + an integer between zero and `n' - 1, inclusive. The following example uses a similar function to produce random integers between one and N. This program prints a new random @@ -14391,9 +14440,17 @@ function call. Starting with version 4.1.2 of `gawk', indirect function calls may also be used with built-in functions and with extension functions -(*note Dynamic Extensions::). The only thing you cannot do is pass a -regular expression constant to a built-in function through an indirect -function call.(1) +(*note Dynamic Extensions::). There are some limitations when calling +built-in functions indirectly, as follows. + + * You cannot pass a regular expression constant to a built-in + function through an indirect function call.(1) This applies to the + `sub()', `gsub()', `gensub()', `match()', `split()' and + `patsplit()' functions. + + * If calling `sub()' or `gsub()', you may only pass two arguments, + since those functions are unusual in that they update their third + argument. This means that `$0' will be updated. `gawk' does its best to make indirect function calls efficient. For example, in the following case: @@ -22973,6 +23030,7 @@ describes the API in detail. * Symbol Table Access:: Functions for accessing global variables. * Array Manipulation:: Functions for working with arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. @@ -23033,6 +23091,9 @@ operations: - Flattening an array for easy C-style looping over all its indices and elements + * Accessing and manipulating redirections. + + Some points about using the API: * The following types, macros, and/or functions are referenced in @@ -24244,7 +24305,7 @@ using `release_value()'. `double' to store. -File: gawk.info, Node: Array Manipulation, Next: Extension API Variables, Prev: Symbol Table Access, Up: Extension API Description +File: gawk.info, Node: Array Manipulation, Next: Redirection API, Prev: Symbol Table Access, Up: Extension API Description 16.4.11 Array Manipulation -------------------------- @@ -24729,9 +24790,78 @@ array: environment variable.) -File: gawk.info, Node: Extension API Variables, Next: Extension API Boilerplate, Prev: Array Manipulation, Up: Extension API Description +File: gawk.info, Node: Redirection API, Next: Extension API Variables, Prev: Array Manipulation, Up: Extension API Description + +16.4.12 Accessing and Manipulating Redirections +----------------------------------------------- + +The following function allows extensions to access and manipulate +redirections. + +`awk_bool_t get_file(const char *name,' +` size_t name_len,' +` const char *filetype,' +` int fd,' +` const awk_input_buf_t **ibufp,' +` const awk_output_buf_t **obufp);' + Look up a file in `gawk''s internal redirection table. If `name' + is `NULL' or `name_len' is zero, return data for the currently + open input file corresponding to `FILENAME'. (This does not + access the `filetype' argument, so that may be undefined). If the + file is not already open, attempt to open it. The `filetype' + argument must be zero-terminated and should be one of: -16.4.12 API Variables + `">"' + A file opened for output. + + `">>"' + A file opened for append. + + `"<"' + A file opened for input. + + `"|>"' + A pipe opened for output. + + `"|<"' + A pipe opened for input. + + `"|&"' + A two-way coprocess. + + On error, return a `false' value. Otherwise, return `true', and + return additional information about the redirection in the `ibufp' + and `obufp' pointers. For input redirections, the `*ibufp' value + should be non-`NULL', and `*obufp' should be `NULL'. For output + redirections, the `*obufp' value should be non-`NULL', and `*ibufp' + should be `NULL'. For two-way coprocesses, both values should be + non-`NULL'. + + In the usual case, the extension is interested in `(*ibufp)->fd' + and/or `fileno((*obufp)->fp)'. If the file is not already open, + and the `fd' argument is non-negative, `gawk' will use that file + descriptor instead of opening the file in the usual way. If `fd' + is non-negative, but the file exists already, `gawk' ignores `fd' + and returns the existing file. It is the caller's responsibility + to notice that neither the `fd' in the returned `awk_input_buf_t' + nor the `fd' in the returned `awk_output_buf_t' matches the + requested value. + + Note that supplying a file descriptor is currently _not_ supported + for pipes. However, supplying a file descriptor should work for + input, output, append, and two-way (coprocess) sockets. If + `filetype' is two-way, `gawk' assumes that it is a socket! Note + that in the two-way case, the input and output file descriptors + may differ. To check for success, you must check whether either + matches. + + It is anticipated that this API function will be used to implement +I/O multiplexing and a socket library. + + +File: gawk.info, Node: Extension API Variables, Next: Extension API Boilerplate, Prev: Redirection API, Up: Extension API Description + +16.4.13 API Variables --------------------- The API provides two sets of variables. The first provides information @@ -24748,7 +24878,7 @@ information about how `gawk' was invoked. File: gawk.info, Node: Extension Versioning, Next: Extension API Informational Variables, Up: Extension API Variables -16.4.12.1 API Version Constants and Variables +16.4.13.1 API Version Constants and Variables ............................................. The API provides both a "major" and a "minor" version number. The API @@ -24797,7 +24927,7 @@ Boilerplate::). File: gawk.info, Node: Extension API Informational Variables, Prev: Extension Versioning, Up: Extension API Variables -16.4.12.2 Informational Variables +16.4.13.2 Informational Variables ................................. The API provides access to several variables that describe whether the @@ -24832,7 +24962,7 @@ not change during execution. File: gawk.info, Node: Extension API Boilerplate, Prev: Extension API Variables, Up: Extension API Description -16.4.13 Boilerplate Code +16.4.14 Boilerplate Code ------------------------ As mentioned earlier (*note Extension Mechanism Outline::), the function @@ -26137,15 +26267,17 @@ project. * GD graphics library extension + * MPFR library extension (this provides access to a number of MPFR + functions that `gawk''s native MPFR support does not) + * PDF extension * PostgreSQL extension - * MPFR library extension (this provides access to a number of MPFR - functions that `gawk''s native MPFR support does not) - * Redis extension + * Select extension + * XML parser extension, using the Expat (http://expat.sourceforge.net) XML parsing library @@ -26289,12 +26421,26 @@ File: gawk.info, Node: Extension Exercises, Prev: Extension summary, Up: Dyna `chmod()', and `umask()' to the file operations extension presented in *note Internal File Ops::. - 2. (Hard.) How would you provide namespaces in `gawk', so that the + 2. Write an input parser that prints a prompt if the input is a from + a "terminal" device. You can use the `isatty()' function to tell + if the input file is a terminal. (Hint: this function is usually + expensive to call; try to call it just once.) The content of the + prompt should come from a variable settable by `awk'-level code. + You can write the prompt to stanard error. However, for best + results, open a new file descriptor (or file pointer) on + `/dev/tty' and print the prompt there, in case standard error has + been redirected. + + Why is standard error a better choice than standard output for + writing the prompt? Which reading mechanism should you replace, + the one to get a record, or the one to read raw bytes? + + 3. (Hard.) How would you provide namespaces in `gawk', so that the names of functions in different extensions don't conflict with each other? If you come up with a really good scheme, contact the `gawk' maintainer to tell him about it. - 3. Write a wrapper script that provides an interface similar to `sed + 4. Write a wrapper script that provides an interface similar to `sed -i' for the "inplace" extension presented in *note Extension Sample Inplace::. @@ -32540,9 +32686,9 @@ Index (line 143) * dark corner, exit statement: Exit Statement. (line 30) * dark corner, field separators: Full Line Fields. (line 22) -* dark corner, FILENAME variable <1>: Auto-set. (line 104) +* dark corner, FILENAME variable <1>: Auto-set. (line 109) * dark corner, FILENAME variable: Getline Notes. (line 19) -* dark corner, FNR/NR variables: Auto-set. (line 328) +* dark corner, FNR/NR variables: Auto-set. (line 341) * dark corner, format-control characters: Control Letters. (line 18) * dark corner, FS as null string: Single Character Fields. (line 20) @@ -32736,7 +32882,7 @@ Index * differences in awk and gawk, FIELDWIDTHS variable: User-modified. (line 37) * differences in awk and gawk, FPAT variable: User-modified. (line 43) -* differences in awk and gawk, FUNCTAB variable: Auto-set. (line 130) +* differences in awk and gawk, FUNCTAB variable: Auto-set. (line 135) * differences in awk and gawk, function arguments (gawk): Calling Built-in. (line 16) * differences in awk and gawk, getline command: Getline. (line 19) @@ -32759,7 +32905,7 @@ Index (line 263) * differences in awk and gawk, print/printf statements: Format Modifiers. (line 13) -* differences in awk and gawk, PROCINFO array: Auto-set. (line 144) +* differences in awk and gawk, PROCINFO array: Auto-set. (line 149) * differences in awk and gawk, read timeouts: Read Timeout. (line 6) * differences in awk and gawk, record separators: awk split records. (line 125) @@ -32767,9 +32913,11 @@ Index (line 43) * differences in awk and gawk, regular expressions: Case-sensitivity. (line 26) +* differences in awk and gawk, retrying input: Retrying Input. + (line 6) * differences in awk and gawk, RS/RT variables: gawk split records. (line 58) -* differences in awk and gawk, RT variable: Auto-set. (line 279) +* differences in awk and gawk, RT variable: Auto-set. (line 292) * differences in awk and gawk, single-character fields: Single Character Fields. (line 6) * differences in awk and gawk, split() function: String Functions. @@ -32777,7 +32925,7 @@ Index * differences in awk and gawk, strings: Scalar Constants. (line 20) * differences in awk and gawk, strings, storing: gawk split records. (line 77) -* differences in awk and gawk, SYMTAB variable: Auto-set. (line 283) +* differences in awk and gawk, SYMTAB variable: Auto-set. (line 296) * differences in awk and gawk, TEXTDOMAIN variable: User-modified. (line 151) * differences in awk and gawk, trunc-mod operation: Arithmetic Ops. @@ -32818,8 +32966,8 @@ Index * dynamically loaded extensions: Dynamic Extensions. (line 6) * e debugger command (alias for enable): Breakpoint Control. (line 73) * EBCDIC: Ordinal Functions. (line 45) -* effective group ID of gawk user: Auto-set. (line 149) -* effective user ID of gawk user: Auto-set. (line 153) +* effective group ID of gawk user: Auto-set. (line 154) +* effective user ID of gawk user: Auto-set. (line 162) * egrep utility <1>: Egrep Program. (line 6) * egrep utility: Bracket Expressions. (line 26) * egrep.awk program: Egrep Program. (line 54) @@ -32915,7 +33063,7 @@ Index (line 99) * exp: Numeric Functions. (line 33) * expand utility: Very Simple. (line 73) -* Expat XML parser library: gawkextlib. (line 35) +* Expat XML parser library: gawkextlib. (line 37) * exponent: Numeric Functions. (line 33) * expressions: Expressions. (line 6) * expressions, as patterns: Expression Patterns. (line 6) @@ -32934,7 +33082,7 @@ Index (line 6) * extension API version: Extension Versioning. (line 6) -* extension API, version number: Auto-set. (line 246) +* extension API, version number: Auto-set. (line 255) * extension example: Extension Example. (line 6) * extension registration: Registration Functions. (line 6) @@ -33015,7 +33163,7 @@ Index * file names, distinguishing: Auto-set. (line 56) * file names, in compatibility mode: Special Caveats. (line 9) * file names, standard streams in gawk: Special FD. (line 48) -* FILENAME variable <1>: Auto-set. (line 104) +* FILENAME variable <1>: Auto-set. (line 109) * FILENAME variable: Reading Files. (line 6) * FILENAME variable, getline, setting with: Getline Notes. (line 19) * filenames, assignments as: Ignoring Assigns. (line 6) @@ -33083,9 +33231,9 @@ Index * flush buffered output: I/O Functions. (line 28) * fnmatch() extension function: Extension Sample Fnmatch. (line 12) -* FNR variable <1>: Auto-set. (line 114) +* FNR variable <1>: Auto-set. (line 119) * FNR variable: Records. (line 6) -* FNR variable, changing: Auto-set. (line 328) +* FNR variable, changing: Auto-set. (line 341) * for statement: For Statement. (line 6) * for statement, looping over arrays: Scanning an Array. (line 20) * fork() extension function: Extension Sample Fork. @@ -33135,7 +33283,7 @@ Index * FSF (Free Software Foundation): Manual History. (line 6) * fts() extension function: Extension Sample File Functions. (line 61) -* FUNCTAB array: Auto-set. (line 130) +* FUNCTAB array: Auto-set. (line 135) * function calls: Function Calls. (line 6) * function calls, indirect: Indirect Calls. (line 6) * function calls, indirect, @-notation for: Indirect Calls. (line 47) @@ -33185,7 +33333,7 @@ Index * G-d: Acknowledgments. (line 94) * Garfinkle, Scott: Contributors. (line 34) * gawk program, dynamic profiling: Profiling. (line 178) -* gawk version: Auto-set. (line 221) +* gawk version: Auto-set. (line 230) * gawk, ARGIND variable in: Other Arguments. (line 15) * gawk, awk and <1>: This Manual. (line 14) * gawk, awk and: Preface. (line 21) @@ -33220,7 +33368,7 @@ Index * gawk, FPAT variable in <1>: User-modified. (line 43) * gawk, FPAT variable in: Splitting By Content. (line 25) -* gawk, FUNCTAB array in: Auto-set. (line 130) +* gawk, FUNCTAB array in: Auto-set. (line 135) * gawk, function arguments and: Calling Built-in. (line 16) * gawk, hexadecimal numbers and: Nondecimal-numbers. (line 42) * gawk, IGNORECASE variable in <1>: Array Sorting Functions. @@ -33252,7 +33400,7 @@ Index * gawk, predefined variables and: Built-in Variables. (line 14) * gawk, PROCINFO array in <1>: Two-way I/O. (line 99) * gawk, PROCINFO array in <2>: Time Functions. (line 47) -* gawk, PROCINFO array in: Auto-set. (line 144) +* gawk, PROCINFO array in: Auto-set. (line 149) * gawk, regexp constants and: Using Constant Regexps. (line 28) * gawk, regular expressions, case sensitivity: Case-sensitivity. @@ -33260,14 +33408,14 @@ Index * gawk, regular expressions, operators: GNU Regexp Operators. (line 6) * gawk, regular expressions, precedence: Regexp Operators. (line 161) -* gawk, RT variable in <1>: Auto-set. (line 279) +* gawk, RT variable in <1>: Auto-set. (line 292) * gawk, RT variable in <2>: Multiple Line. (line 129) * gawk, RT variable in: awk split records. (line 125) * gawk, See Also awk: Preface. (line 34) * gawk, source code, obtaining: Getting. (line 6) * gawk, splitting fields and: Constant Size. (line 87) * gawk, string-translation functions: I18N Functions. (line 6) -* gawk, SYMTAB array in: Auto-set. (line 283) +* gawk, SYMTAB array in: Auto-set. (line 296) * gawk, TEXTDOMAIN variable in: User-modified. (line 151) * gawk, timestamps: Time Functions. (line 6) * gawk, uses for: Preface. (line 34) @@ -33335,7 +33483,7 @@ Index * git utility <2>: Accessing The Source. (line 10) * git utility <3>: Other Versions. (line 29) -* git utility: gawkextlib. (line 29) +* git utility: gawkextlib. (line 31) * Git, use of for gawk source code: Derived Files. (line 6) * GNITS mailing list: Acknowledgments. (line 52) * GNU awk, See gawk: Preface. (line 51) @@ -33359,7 +33507,7 @@ Index * Grigera, Juan: Contributors. (line 57) * group database, reading: Group Functions. (line 6) * group file: Group Functions. (line 6) -* group ID of gawk user: Auto-set. (line 194) +* group ID of gawk user: Auto-set. (line 203) * groups, information about: Group Functions. (line 6) * gsub <1>: String Functions. (line 140) * gsub: Using Constant Regexps. @@ -33654,7 +33802,7 @@ Index * mawk utility <3>: Concatenation. (line 36) * mawk utility <4>: Getline/Pipe. (line 62) * mawk utility: Escape Sequences. (line 120) -* maximum precision supported by MPFR library: Auto-set. (line 235) +* maximum precision supported by MPFR library: Auto-set. (line 244) * McIlroy, Doug: Glossary. (line 258) * McPhee, Patrick: Contributors. (line 100) * message object files: Explaining gettext. (line 42) @@ -33667,7 +33815,7 @@ Index * messages from extensions: Printing Messages. (line 6) * metacharacters in regular expressions: Regexp Operators. (line 6) * metacharacters, escape sequences for: Escape Sequences. (line 139) -* minimum precision supported by MPFR library: Auto-set. (line 238) +* minimum precision required by MPFR library: Auto-set. (line 247) * mktime: Time Functions. (line 25) * modifiers, in format specifiers: Format Modifiers. (line 6) * monetary information, localization: Explaining gettext. (line 104) @@ -33716,7 +33864,7 @@ Index (line 47) * nexti debugger command: Debugger Execution Control. (line 49) -* NF variable <1>: Auto-set. (line 119) +* NF variable <1>: Auto-set. (line 124) * NF variable: Fields. (line 33) * NF variable, decrementing: Changing Fields. (line 107) * ni debugger command (alias for nexti): Debugger Execution Control. @@ -33725,9 +33873,9 @@ Index * non-existent array elements: Reference to Elements. (line 23) * not Boolean-logic operator: Boolean Ops. (line 6) -* NR variable <1>: Auto-set. (line 139) +* NR variable <1>: Auto-set. (line 144) * NR variable: Records. (line 6) -* NR variable, changing: Auto-set. (line 328) +* NR variable, changing: Auto-set. (line 341) * null strings <1>: Basic Data Typing. (line 26) * null strings <2>: Truth Values. (line 6) * null strings <3>: Regexp Field Splitting. @@ -33841,7 +33989,7 @@ Index * p debugger command (alias for print): Viewing And Changing Data. (line 36) * Papadopoulos, Panos: Contributors. (line 128) -* parent process ID of gawk process: Auto-set. (line 203) +* parent process ID of gawk process: Auto-set. (line 212) * parentheses (), in a profile: Profiling. (line 146) * parentheses (), regexp operator: Regexp Operators. (line 81) * password file: Passwd Functions. (line 16) @@ -34007,24 +34155,24 @@ Index * printing, unduplicated lines of text: Uniq Program. (line 6) * printing, user information: Id Program. (line 6) * private variables: Library Names. (line 11) -* process group idIDof gawk process: Auto-set. (line 197) -* process ID of gawk process: Auto-set. (line 200) +* process group ID of gawk process: Auto-set. (line 206) +* process ID of gawk process: Auto-set. (line 209) * processes, two-way communications with: Two-way I/O. (line 6) * processing data: Basic High Level. (line 6) * PROCINFO array <1>: Passwd Functions. (line 6) * PROCINFO array <2>: Time Functions. (line 47) -* PROCINFO array: Auto-set. (line 144) +* PROCINFO array: Auto-set. (line 149) * PROCINFO array, and communications via ptys: Two-way I/O. (line 99) * PROCINFO array, and group membership: Group Functions. (line 6) * PROCINFO array, and user and group ID numbers: Id Program. (line 15) * PROCINFO array, testing the field splitting: Passwd Functions. (line 154) -* PROCINFO array, uses: Auto-set. (line 256) +* PROCINFO array, uses: Auto-set. (line 265) * PROCINFO, values of sorted_in: Controlling Scanning. (line 26) * profiling awk programs: Profiling. (line 6) * profiling awk programs, dynamically: Profiling. (line 178) -* program identifiers: Auto-set. (line 162) +* program identifiers: Auto-set. (line 171) * program, definition of: Getting Started. (line 21) * programming conventions, --non-decimal-data option: Nondecimal Data. (line 35) @@ -34159,6 +34307,7 @@ Index * relational operators, See comparison operators: Typing and Comparison. (line 9) * replace in string: String Functions. (line 409) +* retrying input: Retrying Input. (line 6) * return debugger command: Debugger Execution Control. (line 54) * return statement, user-defined functions: Return Statement. (line 6) @@ -34182,7 +34331,7 @@ Index * right shift: Bitwise Functions. (line 53) * right shift, bitwise: Bitwise Functions. (line 32) * Ritchie, Dennis: Basic Data Typing. (line 54) -* RLENGTH variable: Auto-set. (line 266) +* RLENGTH variable: Auto-set. (line 279) * RLENGTH variable, match() function and: String Functions. (line 228) * Robbins, Arnold <1>: Future Extensions. (line 6) * Robbins, Arnold <2>: Bugs. (line 71) @@ -34208,9 +34357,9 @@ Index * RS variable: awk split records. (line 12) * RS variable, multiline records and: Multiple Line. (line 17) * rshift: Bitwise Functions. (line 53) -* RSTART variable: Auto-set. (line 272) +* RSTART variable: Auto-set. (line 285) * RSTART variable, match() function and: String Functions. (line 228) -* RT variable <1>: Auto-set. (line 279) +* RT variable <1>: Auto-set. (line 292) * RT variable <2>: Multiple Line. (line 129) * RT variable: awk split records. (line 125) * Rubin, Paul <1>: Contributors. (line 15) @@ -34230,7 +34379,7 @@ Index * scanning arrays: Scanning an Array. (line 6) * scanning multidimensional arrays: Multiscanning. (line 11) * Schorr, Andrew <1>: Contributors. (line 133) -* Schorr, Andrew <2>: Auto-set. (line 311) +* Schorr, Andrew <2>: Auto-set. (line 324) * Schorr, Andrew: Acknowledgments. (line 60) * Schreiber, Bert: Acknowledgments. (line 38) * Schreiber, Rita: Acknowledgments. (line 38) @@ -34313,7 +34462,7 @@ Index (line 106) * sidebar, Changing FS Does Not Affect the Fields: Full Line Fields. (line 14) -* sidebar, Changing NR and FNR: Auto-set. (line 326) +* sidebar, Changing NR and FNR: Auto-set. (line 339) * sidebar, Controlling Output Buffering with system(): I/O Functions. (line 139) * sidebar, Escape Sequences for Metacharacters: Escape Sequences. @@ -34475,9 +34624,9 @@ Index * substr: String Functions. (line 482) * substring: String Functions. (line 482) * Sumner, Andrew: Other Versions. (line 68) -* supplementary groups of gawk process: Auto-set. (line 251) +* supplementary groups of gawk process: Auto-set. (line 260) * switch statement: Switch Statement. (line 6) -* SYMTAB array: Auto-set. (line 283) +* SYMTAB array: Auto-set. (line 296) * syntactic ambiguity: /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) * system: I/O Functions. (line 107) @@ -34654,10 +34803,10 @@ Index * variables, uninitialized, as array subscripts: Uninitialized Subscripts. (line 6) * variables, user-defined: Variables. (line 6) -* version of gawk: Auto-set. (line 221) -* version of gawk extension API: Auto-set. (line 246) -* version of GNU MP library: Auto-set. (line 232) -* version of GNU MPFR library: Auto-set. (line 228) +* version of gawk: Auto-set. (line 230) +* version of gawk extension API: Auto-set. (line 255) +* version of GNU MP library: Auto-set. (line 241) +* version of GNU MPFR library: Auto-set. (line 237) * vertical bar (|): Regexp Operators. (line 70) * vertical bar (|), | operator (I/O) <1>: Precedence. (line 65) * vertical bar (|), | operator (I/O): Getline/Pipe. (line 9) @@ -34747,561 +34896,563 @@ Index Tag Table: Node: Top1204 -Node: Foreword342291 -Node: Foreword446735 -Node: Preface48266 -Ref: Preface-Footnote-151137 -Ref: Preface-Footnote-251244 -Ref: Preface-Footnote-351477 -Node: History51619 -Node: Names53970 -Ref: Names-Footnote-155064 -Node: This Manual55210 -Ref: This Manual-Footnote-161710 -Node: Conventions61810 -Node: Manual History64147 -Ref: Manual History-Footnote-167140 -Ref: Manual History-Footnote-267181 -Node: How To Contribute67255 -Node: Acknowledgments68384 -Node: Getting Started73250 -Node: Running gawk75689 -Node: One-shot76879 -Node: Read Terminal78143 -Node: Long80174 -Node: Executable Scripts81687 -Ref: Executable Scripts-Footnote-184476 -Node: Comments84579 -Node: Quoting87061 -Node: DOS Quoting92579 -Node: Sample Data Files93254 -Node: Very Simple95849 -Node: Two Rules100748 -Node: More Complex102634 -Node: Statements/Lines105496 -Ref: Statements/Lines-Footnote-1109951 -Node: Other Features110216 -Node: When111152 -Ref: When-Footnote-1112906 -Node: Intro Summary112971 -Node: Invoking Gawk113855 -Node: Command Line115369 -Node: Options116167 -Ref: Options-Footnote-1131962 -Ref: Options-Footnote-2132191 -Node: Other Arguments132216 -Node: Naming Standard Input135164 -Node: Environment Variables136257 -Node: AWKPATH Variable136815 -Ref: AWKPATH Variable-Footnote-1140222 -Ref: AWKPATH Variable-Footnote-2140267 -Node: AWKLIBPATH Variable140527 -Node: Other Environment Variables141783 -Node: Exit Status145414 -Node: Include Files146090 -Node: Loading Shared Libraries149679 -Node: Obsolete151106 -Node: Undocumented151798 -Node: Invoking Summary152065 -Node: Regexp153728 -Node: Regexp Usage155182 -Node: Escape Sequences157219 -Node: Regexp Operators163448 -Ref: Regexp Operators-Footnote-1170858 -Ref: Regexp Operators-Footnote-2171005 -Node: Bracket Expressions171103 -Ref: table-char-classes173118 -Node: Leftmost Longest176060 -Node: Computed Regexps177362 -Node: GNU Regexp Operators180791 -Node: Case-sensitivity184463 -Ref: Case-sensitivity-Footnote-1187348 -Ref: Case-sensitivity-Footnote-2187583 -Node: Regexp Summary187691 -Node: Reading Files189158 -Node: Records191251 -Node: awk split records191984 -Node: gawk split records196913 -Ref: gawk split records-Footnote-1201452 -Node: Fields201489 -Ref: Fields-Footnote-1204267 -Node: Nonconstant Fields204353 -Ref: Nonconstant Fields-Footnote-1206591 -Node: Changing Fields206794 -Node: Field Separators212725 -Node: Default Field Splitting215429 -Node: Regexp Field Splitting216546 -Node: Single Character Fields219896 -Node: Command Line Field Separator220955 -Node: Full Line Fields224172 -Ref: Full Line Fields-Footnote-1225693 -Ref: Full Line Fields-Footnote-2225739 -Node: Field Splitting Summary225840 -Node: Constant Size227914 -Node: Splitting By Content232493 -Ref: Splitting By Content-Footnote-1236458 -Node: Multiple Line236621 -Ref: Multiple Line-Footnote-1242502 -Node: Getline242681 -Node: Plain Getline244888 -Node: Getline/Variable247528 -Node: Getline/File248677 -Node: Getline/Variable/File250062 -Ref: Getline/Variable/File-Footnote-1251665 -Node: Getline/Pipe251752 -Node: Getline/Variable/Pipe254430 -Node: Getline/Coprocess255561 -Node: Getline/Variable/Coprocess256825 -Node: Getline Notes257564 -Node: Getline Summary260358 -Ref: table-getline-variants260770 -Node: Read Timeout261599 -Ref: Read Timeout-Footnote-1265436 -Node: Command-line directories265494 -Node: Input Summary266399 -Node: Input Exercises269784 -Node: Printing270512 -Node: Print272347 -Node: Print Examples273804 -Node: Output Separators276583 -Node: OFMT278601 -Node: Printf279956 -Node: Basic Printf280741 -Node: Control Letters282313 -Node: Format Modifiers286298 -Node: Printf Examples292304 -Node: Redirection294790 -Node: Special FD301628 -Ref: Special FD-Footnote-1304794 -Node: Special Files304868 -Node: Other Inherited Files305485 -Node: Special Network306485 -Node: Special Caveats307347 -Node: Close Files And Pipes308296 -Ref: Close Files And Pipes-Footnote-1315481 -Ref: Close Files And Pipes-Footnote-2315629 -Node: Nonfatal315779 -Node: Output Summary318104 -Node: Output Exercises319325 -Node: Expressions320005 -Node: Values321194 -Node: Constants321871 -Node: Scalar Constants322562 -Ref: Scalar Constants-Footnote-1323424 -Node: Nondecimal-numbers323674 -Node: Regexp Constants326684 -Node: Using Constant Regexps327210 -Node: Variables330373 -Node: Using Variables331030 -Node: Assignment Options332941 -Node: Conversion334816 -Node: Strings And Numbers335340 -Ref: Strings And Numbers-Footnote-1338405 -Node: Locale influences conversions338514 -Ref: table-locale-affects341260 -Node: All Operators341852 -Node: Arithmetic Ops342481 -Node: Concatenation344986 -Ref: Concatenation-Footnote-1347805 -Node: Assignment Ops347912 -Ref: table-assign-ops352891 -Node: Increment Ops354201 -Node: Truth Values and Conditions357632 -Node: Truth Values358715 -Node: Typing and Comparison359764 -Node: Variable Typing360580 -Node: Comparison Operators364247 -Ref: table-relational-ops364657 -Node: POSIX String Comparison368152 -Ref: POSIX String Comparison-Footnote-1369224 -Node: Boolean Ops369363 -Ref: Boolean Ops-Footnote-1373841 -Node: Conditional Exp373932 -Node: Function Calls375670 -Node: Precedence379550 -Node: Locales383210 -Node: Expressions Summary384842 -Node: Patterns and Actions387413 -Node: Pattern Overview388533 -Node: Regexp Patterns390212 -Node: Expression Patterns390755 -Node: Ranges394535 -Node: BEGIN/END397642 -Node: Using BEGIN/END398403 -Ref: Using BEGIN/END-Footnote-1401139 -Node: I/O And BEGIN/END401245 -Node: BEGINFILE/ENDFILE403560 -Node: Empty406457 -Node: Using Shell Variables406774 -Node: Action Overview409047 -Node: Statements411373 -Node: If Statement413221 -Node: While Statement414716 -Node: Do Statement416744 -Node: For Statement417892 -Node: Switch Statement421050 -Node: Break Statement423432 -Node: Continue Statement425525 -Node: Next Statement427352 -Node: Nextfile Statement429733 -Node: Exit Statement432361 -Node: Built-in Variables434772 -Node: User-modified435905 -Ref: User-modified-Footnote-1443539 -Node: Auto-set443601 -Ref: Auto-set-Footnote-1457310 -Ref: Auto-set-Footnote-2457515 -Node: ARGC and ARGV457571 -Node: Pattern Action Summary461789 -Node: Arrays464222 -Node: Array Basics465551 -Node: Array Intro466395 -Ref: figure-array-elements468332 -Ref: Array Intro-Footnote-1470955 -Node: Reference to Elements471083 -Node: Assigning Elements473545 -Node: Array Example474036 -Node: Scanning an Array475795 -Node: Controlling Scanning478818 -Ref: Controlling Scanning-Footnote-1484212 -Node: Numeric Array Subscripts484528 -Node: Uninitialized Subscripts486713 -Node: Delete488330 -Ref: Delete-Footnote-1491079 -Node: Multidimensional491136 -Node: Multiscanning494233 -Node: Arrays of Arrays495822 -Node: Arrays Summary500576 -Node: Functions502667 -Node: Built-in503706 -Node: Calling Built-in504784 -Node: Numeric Functions506779 -Ref: Numeric Functions-Footnote-1511597 -Ref: Numeric Functions-Footnote-2511954 -Ref: Numeric Functions-Footnote-3512002 -Node: String Functions512274 -Ref: String Functions-Footnote-1535775 -Ref: String Functions-Footnote-2535904 -Ref: String Functions-Footnote-3536152 -Node: Gory Details536239 -Ref: table-sub-escapes538020 -Ref: table-sub-proposed539535 -Ref: table-posix-sub540897 -Ref: table-gensub-escapes542434 -Ref: Gory Details-Footnote-1543267 -Node: I/O Functions543418 -Ref: I/O Functions-Footnote-1550654 -Node: Time Functions550801 -Ref: Time Functions-Footnote-1561310 -Ref: Time Functions-Footnote-2561378 -Ref: Time Functions-Footnote-3561536 -Ref: Time Functions-Footnote-4561647 -Ref: Time Functions-Footnote-5561759 -Ref: Time Functions-Footnote-6561986 -Node: Bitwise Functions562252 -Ref: table-bitwise-ops562814 -Ref: Bitwise Functions-Footnote-1567142 -Node: Type Functions567314 -Node: I18N Functions568466 -Node: User-defined570113 -Node: Definition Syntax570918 -Ref: Definition Syntax-Footnote-1576577 -Node: Function Example576648 -Ref: Function Example-Footnote-1579569 -Node: Function Caveats579591 -Node: Calling A Function580109 -Node: Variable Scope581067 -Node: Pass By Value/Reference584060 -Node: Return Statement587557 -Node: Dynamic Typing590536 -Node: Indirect Calls591465 -Ref: Indirect Calls-Footnote-1601330 -Node: Functions Summary601458 -Node: Library Functions604160 -Ref: Library Functions-Footnote-1607768 -Ref: Library Functions-Footnote-2607911 -Node: Library Names608082 -Ref: Library Names-Footnote-1611540 -Ref: Library Names-Footnote-2611763 -Node: General Functions611849 -Node: Strtonum Function612952 -Node: Assert Function615974 -Node: Round Function619298 -Node: Cliff Random Function620839 -Node: Ordinal Functions621855 -Ref: Ordinal Functions-Footnote-1624918 -Ref: Ordinal Functions-Footnote-2625170 -Node: Join Function625381 -Ref: Join Function-Footnote-1627151 -Node: Getlocaltime Function627351 -Node: Readfile Function631095 -Node: Shell Quoting633067 -Node: Data File Management634468 -Node: Filetrans Function635100 -Node: Rewind Function639196 -Node: File Checking640582 -Ref: File Checking-Footnote-1641915 -Node: Empty Files642116 -Node: Ignoring Assigns644095 -Node: Getopt Function645645 -Ref: Getopt Function-Footnote-1657109 -Node: Passwd Functions657309 -Ref: Passwd Functions-Footnote-1666149 -Node: Group Functions666237 -Ref: Group Functions-Footnote-1674134 -Node: Walking Arrays674339 -Node: Library Functions Summary677345 -Node: Library Exercises678747 -Node: Sample Programs680027 -Node: Running Examples680797 -Node: Clones681525 -Node: Cut Program682749 -Node: Egrep Program692469 -Ref: Egrep Program-Footnote-1699972 -Node: Id Program700082 -Node: Split Program703758 -Ref: Split Program-Footnote-1707212 -Node: Tee Program707340 -Node: Uniq Program710129 -Node: Wc Program717548 -Ref: Wc Program-Footnote-1721798 -Node: Miscellaneous Programs721892 -Node: Dupword Program723105 -Node: Alarm Program725136 -Node: Translate Program729941 -Ref: Translate Program-Footnote-1734504 -Node: Labels Program734774 -Ref: Labels Program-Footnote-1738125 -Node: Word Sorting738209 -Node: History Sorting742279 -Node: Extract Program744114 -Node: Simple Sed751638 -Node: Igawk Program754708 -Ref: Igawk Program-Footnote-1769034 -Ref: Igawk Program-Footnote-2769235 -Ref: Igawk Program-Footnote-3769357 -Node: Anagram Program769472 -Node: Signature Program772533 -Node: Programs Summary773780 -Node: Programs Exercises775001 -Ref: Programs Exercises-Footnote-1779132 -Node: Advanced Features779223 -Node: Nondecimal Data781205 -Node: Array Sorting782795 -Node: Controlling Array Traversal783495 -Ref: Controlling Array Traversal-Footnote-1791861 -Node: Array Sorting Functions791979 -Ref: Array Sorting Functions-Footnote-1795865 -Node: Two-way I/O796061 -Ref: Two-way I/O-Footnote-1801006 -Ref: Two-way I/O-Footnote-2801192 -Node: TCP/IP Networking801274 -Node: Profiling804146 -Node: Advanced Features Summary812417 -Node: Internationalization814350 -Node: I18N and L10N815830 -Node: Explaining gettext816516 -Ref: Explaining gettext-Footnote-1821541 -Ref: Explaining gettext-Footnote-2821725 -Node: Programmer i18n821890 -Ref: Programmer i18n-Footnote-1826766 -Node: Translator i18n826815 -Node: String Extraction827609 -Ref: String Extraction-Footnote-1828740 -Node: Printf Ordering828826 -Ref: Printf Ordering-Footnote-1831612 -Node: I18N Portability831676 -Ref: I18N Portability-Footnote-1834132 -Node: I18N Example834195 -Ref: I18N Example-Footnote-1836998 -Node: Gawk I18N837070 -Node: I18N Summary837714 -Node: Debugger839054 -Node: Debugging840076 -Node: Debugging Concepts840517 -Node: Debugging Terms842327 -Node: Awk Debugging844899 -Node: Sample Debugging Session845805 -Node: Debugger Invocation846339 -Node: Finding The Bug847724 -Node: List of Debugger Commands854203 -Node: Breakpoint Control855535 -Node: Debugger Execution Control859212 -Node: Viewing And Changing Data862571 -Node: Execution Stack865947 -Node: Debugger Info867582 -Node: Miscellaneous Debugger Commands871627 -Node: Readline Support876628 -Node: Limitations877522 -Node: Debugging Summary879637 -Node: Arbitrary Precision Arithmetic880811 -Node: Computer Arithmetic882227 -Ref: table-numeric-ranges885804 -Ref: Computer Arithmetic-Footnote-1886328 -Node: Math Definitions886385 -Ref: table-ieee-formats889680 -Ref: Math Definitions-Footnote-1890284 -Node: MPFR features890389 -Node: FP Math Caution892060 -Ref: FP Math Caution-Footnote-1893110 -Node: Inexactness of computations893479 -Node: Inexact representation894438 -Node: Comparing FP Values895796 -Node: Errors accumulate896878 -Node: Getting Accuracy898310 -Node: Try To Round901014 -Node: Setting precision901913 -Ref: table-predefined-precision-strings902597 -Node: Setting the rounding mode904426 -Ref: table-gawk-rounding-modes904790 -Ref: Setting the rounding mode-Footnote-1908242 -Node: Arbitrary Precision Integers908421 -Ref: Arbitrary Precision Integers-Footnote-1913319 -Node: POSIX Floating Point Problems913468 -Ref: POSIX Floating Point Problems-Footnote-1917347 -Node: Floating point summary917385 -Node: Dynamic Extensions919572 -Node: Extension Intro921124 -Node: Plugin License922389 -Node: Extension Mechanism Outline923186 -Ref: figure-load-extension923614 -Ref: figure-register-new-function925094 -Ref: figure-call-new-function926098 -Node: Extension API Description928085 -Node: Extension API Functions Introduction929535 -Node: General Data Types934356 -Ref: General Data Types-Footnote-1940256 -Node: Memory Allocation Functions940555 -Ref: Memory Allocation Functions-Footnote-1943394 -Node: Constructor Functions943493 -Node: Registration Functions945232 -Node: Extension Functions945917 -Node: Exit Callback Functions948214 -Node: Extension Version String949462 -Node: Input Parsers950125 -Node: Output Wrappers960000 -Node: Two-way processors964513 -Node: Printing Messages966776 -Ref: Printing Messages-Footnote-1967852 -Node: Updating `ERRNO'968004 -Node: Requesting Values968744 -Ref: table-value-types-returned969471 -Node: Accessing Parameters970428 -Node: Symbol Table Access971662 -Node: Symbol table by name972176 -Node: Symbol table by cookie974196 -Ref: Symbol table by cookie-Footnote-1978341 -Node: Cached values978404 -Ref: Cached values-Footnote-1981900 -Node: Array Manipulation981991 -Ref: Array Manipulation-Footnote-1983089 -Node: Array Data Types983126 -Ref: Array Data Types-Footnote-1985781 -Node: Array Functions985873 -Node: Flattening Arrays989732 -Node: Creating Arrays996634 -Node: Extension API Variables1001405 -Node: Extension Versioning1002041 -Node: Extension API Informational Variables1003932 -Node: Extension API Boilerplate1004997 -Node: Finding Extensions1008806 -Node: Extension Example1009366 -Node: Internal File Description1010138 -Node: Internal File Ops1014205 -Ref: Internal File Ops-Footnote-11025956 -Node: Using Internal File Ops1026096 -Ref: Using Internal File Ops-Footnote-11028479 -Node: Extension Samples1028752 -Node: Extension Sample File Functions1030280 -Node: Extension Sample Fnmatch1037961 -Node: Extension Sample Fork1039449 -Node: Extension Sample Inplace1040664 -Node: Extension Sample Ord1042750 -Node: Extension Sample Readdir1043586 -Ref: table-readdir-file-types1044463 -Node: Extension Sample Revout1045274 -Node: Extension Sample Rev2way1045863 -Node: Extension Sample Read write array1046603 -Node: Extension Sample Readfile1048543 -Node: Extension Sample Time1049638 -Node: Extension Sample API Tests1050986 -Node: gawkextlib1051477 -Node: Extension summary1054155 -Node: Extension Exercises1057844 -Node: Language History1058566 -Node: V7/SVR3.11060222 -Node: SVR41062375 -Node: POSIX1063809 -Node: BTL1065190 -Node: POSIX/GNU1065921 -Node: Feature History1071757 -Node: Common Extensions1085551 -Node: Ranges and Locales1086923 -Ref: Ranges and Locales-Footnote-11091542 -Ref: Ranges and Locales-Footnote-21091569 -Ref: Ranges and Locales-Footnote-31091804 -Node: Contributors1092025 -Node: History summary1097565 -Node: Installation1098944 -Node: Gawk Distribution1099890 -Node: Getting1100374 -Node: Extracting1101197 -Node: Distribution contents1102834 -Node: Unix Installation1108936 -Node: Quick Installation1109619 -Node: Shell Startup Files1112030 -Node: Additional Configuration Options1113109 -Node: Configuration Philosophy1114913 -Node: Non-Unix Installation1117282 -Node: PC Installation1117740 -Node: PC Binary Installation1119060 -Node: PC Compiling1120908 -Ref: PC Compiling-Footnote-11123929 -Node: PC Testing1124038 -Node: PC Using1125214 -Node: Cygwin1129329 -Node: MSYS1130099 -Node: VMS Installation1130600 -Node: VMS Compilation1131392 -Ref: VMS Compilation-Footnote-11132621 -Node: VMS Dynamic Extensions1132679 -Node: VMS Installation Details1134363 -Node: VMS Running1136614 -Node: VMS GNV1139454 -Node: VMS Old Gawk1140189 -Node: Bugs1140659 -Node: Other Versions1144548 -Node: Installation summary1150982 -Node: Notes1152041 -Node: Compatibility Mode1152906 -Node: Additions1153688 -Node: Accessing The Source1154613 -Node: Adding Code1156048 -Node: New Ports1162205 -Node: Derived Files1166687 -Ref: Derived Files-Footnote-11172162 -Ref: Derived Files-Footnote-21172196 -Ref: Derived Files-Footnote-31172792 -Node: Future Extensions1172906 -Node: Implementation Limitations1173512 -Node: Extension Design1174760 -Node: Old Extension Problems1175914 -Ref: Old Extension Problems-Footnote-11177431 -Node: Extension New Mechanism Goals1177488 -Ref: Extension New Mechanism Goals-Footnote-11180848 -Node: Extension Other Design Decisions1181037 -Node: Extension Future Growth1183145 -Node: Old Extension Mechanism1183981 -Node: Notes summary1185743 -Node: Basic Concepts1186929 -Node: Basic High Level1187610 -Ref: figure-general-flow1187882 -Ref: figure-process-flow1188481 -Ref: Basic High Level-Footnote-11191710 -Node: Basic Data Typing1191895 -Node: Glossary1195223 -Node: Copying1227152 -Node: GNU Free Documentation License1264708 -Node: Index1289844 +Node: Foreword342451 +Node: Foreword446895 +Node: Preface48426 +Ref: Preface-Footnote-151297 +Ref: Preface-Footnote-251404 +Ref: Preface-Footnote-351637 +Node: History51779 +Node: Names54130 +Ref: Names-Footnote-155224 +Node: This Manual55370 +Ref: This Manual-Footnote-161870 +Node: Conventions61970 +Node: Manual History64307 +Ref: Manual History-Footnote-167300 +Ref: Manual History-Footnote-267341 +Node: How To Contribute67415 +Node: Acknowledgments68544 +Node: Getting Started73410 +Node: Running gawk75849 +Node: One-shot77039 +Node: Read Terminal78303 +Node: Long80334 +Node: Executable Scripts81847 +Ref: Executable Scripts-Footnote-184636 +Node: Comments84739 +Node: Quoting87221 +Node: DOS Quoting92739 +Node: Sample Data Files93414 +Node: Very Simple96009 +Node: Two Rules100908 +Node: More Complex102794 +Node: Statements/Lines105656 +Ref: Statements/Lines-Footnote-1110111 +Node: Other Features110376 +Node: When111312 +Ref: When-Footnote-1113066 +Node: Intro Summary113131 +Node: Invoking Gawk114015 +Node: Command Line115529 +Node: Options116327 +Ref: Options-Footnote-1132122 +Ref: Options-Footnote-2132351 +Node: Other Arguments132376 +Node: Naming Standard Input135324 +Node: Environment Variables136417 +Node: AWKPATH Variable136975 +Ref: AWKPATH Variable-Footnote-1140382 +Ref: AWKPATH Variable-Footnote-2140427 +Node: AWKLIBPATH Variable140687 +Node: Other Environment Variables141943 +Node: Exit Status145574 +Node: Include Files146250 +Node: Loading Shared Libraries149839 +Node: Obsolete151266 +Node: Undocumented151958 +Node: Invoking Summary152225 +Node: Regexp153888 +Node: Regexp Usage155342 +Node: Escape Sequences157379 +Node: Regexp Operators163608 +Ref: Regexp Operators-Footnote-1171018 +Ref: Regexp Operators-Footnote-2171165 +Node: Bracket Expressions171263 +Ref: table-char-classes173278 +Node: Leftmost Longest176220 +Node: Computed Regexps177522 +Node: GNU Regexp Operators180951 +Node: Case-sensitivity184623 +Ref: Case-sensitivity-Footnote-1187508 +Ref: Case-sensitivity-Footnote-2187743 +Node: Regexp Summary187851 +Node: Reading Files189318 +Node: Records191480 +Node: awk split records192213 +Node: gawk split records197142 +Ref: gawk split records-Footnote-1201681 +Node: Fields201718 +Ref: Fields-Footnote-1204496 +Node: Nonconstant Fields204582 +Ref: Nonconstant Fields-Footnote-1206820 +Node: Changing Fields207023 +Node: Field Separators212954 +Node: Default Field Splitting215658 +Node: Regexp Field Splitting216775 +Node: Single Character Fields220125 +Node: Command Line Field Separator221184 +Node: Full Line Fields224401 +Ref: Full Line Fields-Footnote-1225922 +Ref: Full Line Fields-Footnote-2225968 +Node: Field Splitting Summary226069 +Node: Constant Size228143 +Node: Splitting By Content232722 +Ref: Splitting By Content-Footnote-1236687 +Node: Multiple Line236850 +Ref: Multiple Line-Footnote-1242731 +Node: Getline242910 +Node: Plain Getline245380 +Node: Getline/Variable248020 +Node: Getline/File249169 +Node: Getline/Variable/File250554 +Ref: Getline/Variable/File-Footnote-1252157 +Node: Getline/Pipe252244 +Node: Getline/Variable/Pipe254922 +Node: Getline/Coprocess256053 +Node: Getline/Variable/Coprocess257317 +Node: Getline Notes258056 +Node: Getline Summary260850 +Ref: table-getline-variants261262 +Node: Read Timeout262091 +Ref: Read Timeout-Footnote-1265994 +Node: Retrying Input266052 +Node: Command-line directories267251 +Node: Input Summary268158 +Node: Input Exercises271543 +Node: Printing272271 +Node: Print274106 +Node: Print Examples275563 +Node: Output Separators278342 +Node: OFMT280360 +Node: Printf281715 +Node: Basic Printf282500 +Node: Control Letters284072 +Node: Format Modifiers288057 +Node: Printf Examples294063 +Node: Redirection296549 +Node: Special FD303387 +Ref: Special FD-Footnote-1306553 +Node: Special Files306627 +Node: Other Inherited Files307244 +Node: Special Network308244 +Node: Special Caveats309106 +Node: Close Files And Pipes310055 +Ref: Close Files And Pipes-Footnote-1317240 +Ref: Close Files And Pipes-Footnote-2317388 +Node: Nonfatal317538 +Node: Output Summary319863 +Node: Output Exercises321084 +Node: Expressions321764 +Node: Values322953 +Node: Constants323630 +Node: Scalar Constants324321 +Ref: Scalar Constants-Footnote-1325183 +Node: Nondecimal-numbers325433 +Node: Regexp Constants328443 +Node: Using Constant Regexps328969 +Node: Variables332132 +Node: Using Variables332789 +Node: Assignment Options334700 +Node: Conversion336575 +Node: Strings And Numbers337099 +Ref: Strings And Numbers-Footnote-1340164 +Node: Locale influences conversions340273 +Ref: table-locale-affects343019 +Node: All Operators343611 +Node: Arithmetic Ops344240 +Node: Concatenation346745 +Ref: Concatenation-Footnote-1349564 +Node: Assignment Ops349671 +Ref: table-assign-ops354650 +Node: Increment Ops355960 +Node: Truth Values and Conditions359391 +Node: Truth Values360474 +Node: Typing and Comparison361523 +Node: Variable Typing362339 +Node: Comparison Operators366006 +Ref: table-relational-ops366416 +Node: POSIX String Comparison369911 +Ref: POSIX String Comparison-Footnote-1370983 +Node: Boolean Ops371122 +Ref: Boolean Ops-Footnote-1375600 +Node: Conditional Exp375691 +Node: Function Calls377429 +Node: Precedence381309 +Node: Locales384969 +Node: Expressions Summary386601 +Node: Patterns and Actions389172 +Node: Pattern Overview390292 +Node: Regexp Patterns391971 +Node: Expression Patterns392514 +Node: Ranges396294 +Node: BEGIN/END399401 +Node: Using BEGIN/END400162 +Ref: Using BEGIN/END-Footnote-1402898 +Node: I/O And BEGIN/END403004 +Node: BEGINFILE/ENDFILE405319 +Node: Empty408216 +Node: Using Shell Variables408533 +Node: Action Overview410806 +Node: Statements413132 +Node: If Statement414980 +Node: While Statement416475 +Node: Do Statement418503 +Node: For Statement419651 +Node: Switch Statement422809 +Node: Break Statement425191 +Node: Continue Statement427284 +Node: Next Statement429111 +Node: Nextfile Statement431492 +Node: Exit Statement434120 +Node: Built-in Variables436531 +Node: User-modified437664 +Ref: User-modified-Footnote-1445298 +Node: Auto-set445360 +Ref: Auto-set-Footnote-1459593 +Ref: Auto-set-Footnote-2459798 +Node: ARGC and ARGV459854 +Node: Pattern Action Summary464072 +Node: Arrays466505 +Node: Array Basics467834 +Node: Array Intro468678 +Ref: figure-array-elements470615 +Ref: Array Intro-Footnote-1473238 +Node: Reference to Elements473366 +Node: Assigning Elements475828 +Node: Array Example476319 +Node: Scanning an Array478078 +Node: Controlling Scanning481101 +Ref: Controlling Scanning-Footnote-1486495 +Node: Numeric Array Subscripts486811 +Node: Uninitialized Subscripts488996 +Node: Delete490613 +Ref: Delete-Footnote-1493362 +Node: Multidimensional493419 +Node: Multiscanning496516 +Node: Arrays of Arrays498105 +Node: Arrays Summary502859 +Node: Functions504950 +Node: Built-in505989 +Node: Calling Built-in507067 +Node: Numeric Functions509062 +Ref: Numeric Functions-Footnote-1513892 +Ref: Numeric Functions-Footnote-2514249 +Ref: Numeric Functions-Footnote-3514297 +Node: String Functions514569 +Ref: String Functions-Footnote-1538070 +Ref: String Functions-Footnote-2538199 +Ref: String Functions-Footnote-3538447 +Node: Gory Details538534 +Ref: table-sub-escapes540315 +Ref: table-sub-proposed541830 +Ref: table-posix-sub543192 +Ref: table-gensub-escapes544729 +Ref: Gory Details-Footnote-1545562 +Node: I/O Functions545713 +Ref: I/O Functions-Footnote-1552949 +Node: Time Functions553096 +Ref: Time Functions-Footnote-1563605 +Ref: Time Functions-Footnote-2563673 +Ref: Time Functions-Footnote-3563831 +Ref: Time Functions-Footnote-4563942 +Ref: Time Functions-Footnote-5564054 +Ref: Time Functions-Footnote-6564281 +Node: Bitwise Functions564547 +Ref: table-bitwise-ops565109 +Ref: Bitwise Functions-Footnote-1569437 +Node: Type Functions569609 +Node: I18N Functions570761 +Node: User-defined572408 +Node: Definition Syntax573213 +Ref: Definition Syntax-Footnote-1578872 +Node: Function Example578943 +Ref: Function Example-Footnote-1581864 +Node: Function Caveats581886 +Node: Calling A Function582404 +Node: Variable Scope583362 +Node: Pass By Value/Reference586355 +Node: Return Statement589852 +Node: Dynamic Typing592831 +Node: Indirect Calls593760 +Ref: Indirect Calls-Footnote-1604003 +Node: Functions Summary604131 +Node: Library Functions606833 +Ref: Library Functions-Footnote-1610441 +Ref: Library Functions-Footnote-2610584 +Node: Library Names610755 +Ref: Library Names-Footnote-1614213 +Ref: Library Names-Footnote-2614436 +Node: General Functions614522 +Node: Strtonum Function615625 +Node: Assert Function618647 +Node: Round Function621971 +Node: Cliff Random Function623512 +Node: Ordinal Functions624528 +Ref: Ordinal Functions-Footnote-1627591 +Ref: Ordinal Functions-Footnote-2627843 +Node: Join Function628054 +Ref: Join Function-Footnote-1629824 +Node: Getlocaltime Function630024 +Node: Readfile Function633768 +Node: Shell Quoting635740 +Node: Data File Management637141 +Node: Filetrans Function637773 +Node: Rewind Function641869 +Node: File Checking643255 +Ref: File Checking-Footnote-1644588 +Node: Empty Files644789 +Node: Ignoring Assigns646768 +Node: Getopt Function648318 +Ref: Getopt Function-Footnote-1659782 +Node: Passwd Functions659982 +Ref: Passwd Functions-Footnote-1668822 +Node: Group Functions668910 +Ref: Group Functions-Footnote-1676807 +Node: Walking Arrays677012 +Node: Library Functions Summary680018 +Node: Library Exercises681420 +Node: Sample Programs682700 +Node: Running Examples683470 +Node: Clones684198 +Node: Cut Program685422 +Node: Egrep Program695142 +Ref: Egrep Program-Footnote-1702645 +Node: Id Program702755 +Node: Split Program706431 +Ref: Split Program-Footnote-1709885 +Node: Tee Program710013 +Node: Uniq Program712802 +Node: Wc Program720221 +Ref: Wc Program-Footnote-1724471 +Node: Miscellaneous Programs724565 +Node: Dupword Program725778 +Node: Alarm Program727809 +Node: Translate Program732614 +Ref: Translate Program-Footnote-1737177 +Node: Labels Program737447 +Ref: Labels Program-Footnote-1740798 +Node: Word Sorting740882 +Node: History Sorting744952 +Node: Extract Program746787 +Node: Simple Sed754311 +Node: Igawk Program757381 +Ref: Igawk Program-Footnote-1771707 +Ref: Igawk Program-Footnote-2771908 +Ref: Igawk Program-Footnote-3772030 +Node: Anagram Program772145 +Node: Signature Program775206 +Node: Programs Summary776453 +Node: Programs Exercises777674 +Ref: Programs Exercises-Footnote-1781805 +Node: Advanced Features781896 +Node: Nondecimal Data783878 +Node: Array Sorting785468 +Node: Controlling Array Traversal786168 +Ref: Controlling Array Traversal-Footnote-1794534 +Node: Array Sorting Functions794652 +Ref: Array Sorting Functions-Footnote-1798538 +Node: Two-way I/O798734 +Ref: Two-way I/O-Footnote-1803679 +Ref: Two-way I/O-Footnote-2803865 +Node: TCP/IP Networking803947 +Node: Profiling806819 +Node: Advanced Features Summary815090 +Node: Internationalization817023 +Node: I18N and L10N818503 +Node: Explaining gettext819189 +Ref: Explaining gettext-Footnote-1824214 +Ref: Explaining gettext-Footnote-2824398 +Node: Programmer i18n824563 +Ref: Programmer i18n-Footnote-1829439 +Node: Translator i18n829488 +Node: String Extraction830282 +Ref: String Extraction-Footnote-1831413 +Node: Printf Ordering831499 +Ref: Printf Ordering-Footnote-1834285 +Node: I18N Portability834349 +Ref: I18N Portability-Footnote-1836805 +Node: I18N Example836868 +Ref: I18N Example-Footnote-1839671 +Node: Gawk I18N839743 +Node: I18N Summary840387 +Node: Debugger841727 +Node: Debugging842749 +Node: Debugging Concepts843190 +Node: Debugging Terms845000 +Node: Awk Debugging847572 +Node: Sample Debugging Session848478 +Node: Debugger Invocation849012 +Node: Finding The Bug850397 +Node: List of Debugger Commands856876 +Node: Breakpoint Control858208 +Node: Debugger Execution Control861885 +Node: Viewing And Changing Data865244 +Node: Execution Stack868620 +Node: Debugger Info870255 +Node: Miscellaneous Debugger Commands874300 +Node: Readline Support879301 +Node: Limitations880195 +Node: Debugging Summary882310 +Node: Arbitrary Precision Arithmetic883484 +Node: Computer Arithmetic884900 +Ref: table-numeric-ranges888477 +Ref: Computer Arithmetic-Footnote-1889001 +Node: Math Definitions889058 +Ref: table-ieee-formats892353 +Ref: Math Definitions-Footnote-1892957 +Node: MPFR features893062 +Node: FP Math Caution894733 +Ref: FP Math Caution-Footnote-1895783 +Node: Inexactness of computations896152 +Node: Inexact representation897111 +Node: Comparing FP Values898469 +Node: Errors accumulate899551 +Node: Getting Accuracy900983 +Node: Try To Round903687 +Node: Setting precision904586 +Ref: table-predefined-precision-strings905270 +Node: Setting the rounding mode907099 +Ref: table-gawk-rounding-modes907463 +Ref: Setting the rounding mode-Footnote-1910915 +Node: Arbitrary Precision Integers911094 +Ref: Arbitrary Precision Integers-Footnote-1915992 +Node: POSIX Floating Point Problems916141 +Ref: POSIX Floating Point Problems-Footnote-1920020 +Node: Floating point summary920058 +Node: Dynamic Extensions922245 +Node: Extension Intro923797 +Node: Plugin License925062 +Node: Extension Mechanism Outline925859 +Ref: figure-load-extension926287 +Ref: figure-register-new-function927767 +Ref: figure-call-new-function928771 +Node: Extension API Description930758 +Node: Extension API Functions Introduction932292 +Node: General Data Types937161 +Ref: General Data Types-Footnote-1943061 +Node: Memory Allocation Functions943360 +Ref: Memory Allocation Functions-Footnote-1946199 +Node: Constructor Functions946298 +Node: Registration Functions948037 +Node: Extension Functions948722 +Node: Exit Callback Functions951019 +Node: Extension Version String952267 +Node: Input Parsers952930 +Node: Output Wrappers962805 +Node: Two-way processors967318 +Node: Printing Messages969581 +Ref: Printing Messages-Footnote-1970657 +Node: Updating `ERRNO'970809 +Node: Requesting Values971549 +Ref: table-value-types-returned972276 +Node: Accessing Parameters973233 +Node: Symbol Table Access974467 +Node: Symbol table by name974981 +Node: Symbol table by cookie977001 +Ref: Symbol table by cookie-Footnote-1981146 +Node: Cached values981209 +Ref: Cached values-Footnote-1984705 +Node: Array Manipulation984796 +Ref: Array Manipulation-Footnote-1985886 +Node: Array Data Types985923 +Ref: Array Data Types-Footnote-1988578 +Node: Array Functions988670 +Node: Flattening Arrays992529 +Node: Creating Arrays999431 +Node: Redirection API1004202 +Node: Extension API Variables1007027 +Node: Extension Versioning1007660 +Node: Extension API Informational Variables1009551 +Node: Extension API Boilerplate1010616 +Node: Finding Extensions1014425 +Node: Extension Example1014985 +Node: Internal File Description1015757 +Node: Internal File Ops1019824 +Ref: Internal File Ops-Footnote-11031575 +Node: Using Internal File Ops1031715 +Ref: Using Internal File Ops-Footnote-11034098 +Node: Extension Samples1034371 +Node: Extension Sample File Functions1035899 +Node: Extension Sample Fnmatch1043580 +Node: Extension Sample Fork1045068 +Node: Extension Sample Inplace1046283 +Node: Extension Sample Ord1048369 +Node: Extension Sample Readdir1049205 +Ref: table-readdir-file-types1050082 +Node: Extension Sample Revout1050893 +Node: Extension Sample Rev2way1051482 +Node: Extension Sample Read write array1052222 +Node: Extension Sample Readfile1054162 +Node: Extension Sample Time1055257 +Node: Extension Sample API Tests1056605 +Node: gawkextlib1057096 +Node: Extension summary1059797 +Node: Extension Exercises1063486 +Node: Language History1064982 +Node: V7/SVR3.11066638 +Node: SVR41068791 +Node: POSIX1070225 +Node: BTL1071606 +Node: POSIX/GNU1072337 +Node: Feature History1078173 +Node: Common Extensions1091967 +Node: Ranges and Locales1093339 +Ref: Ranges and Locales-Footnote-11097958 +Ref: Ranges and Locales-Footnote-21097985 +Ref: Ranges and Locales-Footnote-31098220 +Node: Contributors1098441 +Node: History summary1103981 +Node: Installation1105360 +Node: Gawk Distribution1106306 +Node: Getting1106790 +Node: Extracting1107613 +Node: Distribution contents1109250 +Node: Unix Installation1115352 +Node: Quick Installation1116035 +Node: Shell Startup Files1118446 +Node: Additional Configuration Options1119525 +Node: Configuration Philosophy1121329 +Node: Non-Unix Installation1123698 +Node: PC Installation1124156 +Node: PC Binary Installation1125476 +Node: PC Compiling1127324 +Ref: PC Compiling-Footnote-11130345 +Node: PC Testing1130454 +Node: PC Using1131630 +Node: Cygwin1135745 +Node: MSYS1136515 +Node: VMS Installation1137016 +Node: VMS Compilation1137808 +Ref: VMS Compilation-Footnote-11139037 +Node: VMS Dynamic Extensions1139095 +Node: VMS Installation Details1140779 +Node: VMS Running1143030 +Node: VMS GNV1145870 +Node: VMS Old Gawk1146605 +Node: Bugs1147075 +Node: Other Versions1150964 +Node: Installation summary1157398 +Node: Notes1158457 +Node: Compatibility Mode1159322 +Node: Additions1160104 +Node: Accessing The Source1161029 +Node: Adding Code1162464 +Node: New Ports1168621 +Node: Derived Files1173103 +Ref: Derived Files-Footnote-11178578 +Ref: Derived Files-Footnote-21178612 +Ref: Derived Files-Footnote-31179208 +Node: Future Extensions1179322 +Node: Implementation Limitations1179928 +Node: Extension Design1181176 +Node: Old Extension Problems1182330 +Ref: Old Extension Problems-Footnote-11183847 +Node: Extension New Mechanism Goals1183904 +Ref: Extension New Mechanism Goals-Footnote-11187264 +Node: Extension Other Design Decisions1187453 +Node: Extension Future Growth1189561 +Node: Old Extension Mechanism1190397 +Node: Notes summary1192159 +Node: Basic Concepts1193345 +Node: Basic High Level1194026 +Ref: figure-general-flow1194298 +Ref: figure-process-flow1194897 +Ref: Basic High Level-Footnote-11198126 +Node: Basic Data Typing1198311 +Node: Glossary1201639 +Node: Copying1233568 +Node: GNU Free Documentation License1271124 +Node: Index1296260 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 8005fe3f..f710d725 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -604,6 +604,7 @@ particular records in a file and perform operations upon them. @code{getline}. * Getline Summary:: Summary of @code{getline} Variants. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -945,6 +946,7 @@ particular records in a file and perform operations upon them. * Array Functions:: Functions for working with arrays. * Flattening Arrays:: How to flatten arrays. * Creating Arrays:: How to create and populate arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension Versioning:: API Version information. * Extension API Informational Variables:: Variables providing information about @@ -6327,6 +6329,7 @@ used with it do not have to be named on the @command{awk} command line * Getline:: Reading files under explicit program control using the @code{getline} function. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -8113,6 +8116,13 @@ a record, such as a file that cannot be opened, then @code{getline} returns @minus{}1. In this case, @command{gawk} sets the variable @code{ERRNO} to a string describing the error that occurred. +If @code{ERRNO} indicates that the I/O operation may be +retried, and @code{PROCINFO["@var{input}", "RETRY"]} is set, +then @code{getline} returns @minus{}2 +instead of @minus{}1, and further calls to @code{getline} +may be attemped. @DBXREF{Retrying Input} for further information about +this feature. + In the following examples, @var{command} stands for a string value that represents a shell command. @@ -8767,7 +8777,8 @@ on a per-command or per-connection basis. the attempt to read from the underlying device may succeed in a later attempt. This is a limitation, and it also means that you cannot use this to multiplex input from -two or more sources. +two or more sources. @DBXREF{Retrying Input} for a way to enable +later I/O attempts to succeed. Assigning a timeout value prevents read operations from blocking indefinitely. But bear in mind that there are other ways @@ -8777,6 +8788,36 @@ a connection before it can start reading any data, or the attempt to open a FIFO special file for reading can block indefinitely until some other process opens it for writing. +@node Retrying Input +@section Retrying Reads After Certain Input Errors +@cindex retrying input + +@cindex differences in @command{awk} and @command{gawk}, retrying input +This @value{SECTION} describes a feature that is specific to @command{gawk}. + +When @command{gawk} encounters an error while reading input, by +default @code{getline} returns @minus{}1, and subsequent attempts to +read from that file result in an end-of-file indication. However, you +may optionally instruct @command{gawk} to allow I/O to be retried when +certain errors are encountered by setting a special element in +the @code{PROCINFO} array (@pxref{Auto-set}): + +@example +PROCINFO["@var{input_name}", "RETRY"] = 1 +@end example + +When this element exists, @command{gawk} checks the value of the system +(C language) +@code{errno} variable when an I/O error occurs. If @code{errno} indicates +a subsequent I/O attempt may succeed, @code{getline} instead returns +@minus{}2 and +further calls to @code{getline} may succeed. This applies to the @code{errno} +values @code{EAGAIN}, @code{EWOULDBLOCK}, @code{EINTR}, or @code{ETIMEDOUT}. + +This feature is useful in conjunction with +@code{PROCINFO["@var{input_name}", "READ_TIMEOUT"]} or situations where a file +descriptor has been configured to behave in a non-blocking fashion. + @node Command-line directories @section Directories on the Command Line @cindex differences in @command{awk} and @command{gawk}, command-line directories @@ -14928,6 +14969,11 @@ value to be meaningful when an I/O operation returns a failure value, such as @code{getline} returning @minus{}1. You are, of course, free to clear it yourself before doing an I/O operation. +If the value of @code{ERRNO} corresponds to a system error in the C +@code{errno} variable, then @code{PROCINFO["errno"]} will be set to the value +of @code{errno}. For non-system errors, @code{PROCINFO["errno"]} will +be zero. + @cindex @code{FILENAME} variable @cindex dark corner, @code{FILENAME} variable @item @code{FILENAME} @@ -14996,6 +15042,10 @@ are guaranteed to be available: @item PROCINFO["egid"] The value of the @code{getegid()} system call. +@item PROCINFO["errno"] +The value of the C @code{errno} variable when @code{ERRNO} is set to +the associated error message. + @item PROCINFO["euid"] @cindex effective user ID of @command{gawk} user The value of the @code{geteuid()} system call. @@ -15046,7 +15096,7 @@ while the program runs. The value of the @code{getgid()} system call. @item PROCINFO["pgrpid"] -@cindex process group idIDof @command{gawk} process +@cindex process group ID of @command{gawk} process The process group ID of the current process. @item PROCINFO["pid"] @@ -15098,7 +15148,7 @@ The version of the GNU MP library. The maximum precision supported by MPFR. @item PROCINFO["prec_min"] -@cindex minimum precision supported by MPFR library +@cindex minimum precision required by MPFR library The minimum precision required by MPFR. @end table @@ -15135,6 +15185,11 @@ open input file, pipe, or coprocess. @DBXREF{Read Timeout} for more information. @item +It may be used to indicate that input may be retried when it fails due to +certain errors. +@DBXREF{Retrying Input} for more information. + +@item It may be used to cause coprocesses to communicate over pseudo-ttys instead of through two-way pipes; this is discussed further in @ref{Two-way I/O}. @@ -17098,8 +17153,8 @@ function randint(n) @end example @noindent -The multiplication produces a random number greater than zero and less -than @code{n}. Using @code{int()}, this result is made into +The multiplication produces a random number greater than or equal to +zero and less than @code{n}. Using @code{int()}, this result is made into an integer between zero and @code{n} @minus{} 1, inclusive. The following example uses a similar function to produce random integers @@ -20451,10 +20506,23 @@ Remember that you must supply a leading @samp{@@} in front of an indirect functi Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function calls may also be used with built-in functions and with extension functions -(@pxref{Dynamic Extensions}). The only thing you cannot do is pass a regular -expression constant to a built-in function through an indirect function -call.@footnote{This may change in a future version; recheck the documentation that -comes with your version of @command{gawk} to see if it has.} +(@pxref{Dynamic Extensions}). There are some limitations when calling +built-in functions indirectly, as follows. + +@itemize @value{BULLET} +@item +You cannot pass a regular expression constant to a built-in function +through an indirect function call.@footnote{This may change in a future +version; recheck the documentation that comes with your version of +@command{gawk} to see if it has.} This applies to the @code{sub()}, +@code{gsub()}, @code{gensub()}, @code{match()}, @code{split()} and +@code{patsplit()} functions. + +@item +If calling @code{sub()} or @code{gsub()}, you may only pass two arguments, +since those functions are unusual in that they update their third argument. +This means that @code{$0} will be updated. +@end itemize @command{gawk} does its best to make indirect function calls efficient. For example, in the following case: @@ -31571,6 +31639,7 @@ This (rather large) @value{SECTION} describes the API in detail. * Symbol Table Access:: Functions for accessing global variables. * Array Manipulation:: Functions for working with arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. @end menu @@ -31646,6 +31715,10 @@ Clearing an array @item Flattening an array for easy C-style looping over all its indices and elements @end itemize + +@item +Accessing and manipulating redirections. + @end itemize Some points about using the API: @@ -33616,6 +33689,75 @@ $ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk} (@DBXREF{Finding Extensions} for more information on the @env{AWKLIBPATH} environment variable.) +@node Redirection API +@subsection Accessing and Manipulating Redirections + +The following function allows extensions to access and manipulate redirections. + +@table @code +@item awk_bool_t get_file(const char *name, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t name_len, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *filetype, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int fd, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_input_buf_t **ibufp, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_output_buf_t **obufp); +Look up a file in @command{gawk}'s internal redirection table. +If @code{name} is @code{NULL} or @code{name_len} is zero, return +data for the currently open input file corresponding to @code{FILENAME}. +(This does not access the @code{filetype} argument, so that may be undefined). +If the file is not already open, attempt to open it. +The @code{filetype} argument must be zero-terminated and should be one of: + +@table @code +@item ">" +A file opened for output. + +@item ">>" +A file opened for append. + +@item "<" +A file opened for input. + +@item "|>" +A pipe opened for output. + +@item "|<" +A pipe opened for input. + +@item "|&" +A two-way coprocess. +@end table + +On error, return a @code{false} value. Otherwise, return +@code{true}, and return additional information about the redirection +in the @code{ibufp} and @code{obufp} pointers. For input +redirections, the @code{*ibufp} value should be non-@code{NULL}, +and @code{*obufp} should be @code{NULL}. For output redirections, +the @code{*obufp} value should be non-@code{NULL}, and @code{*ibufp} +should be @code{NULL}. For two-way coprocesses, both values should +be non-@code{NULL}. + +In the usual case, the extension is interested in @code{(*ibufp)->fd} +and/or @code{fileno((*obufp)->fp)}. If the file is not already +open, and the @code{fd} argument is non-negative, @command{gawk} +will use that file descriptor instead of opening the file in the +usual way. If @code{fd} is non-negative, but the file exists already, +@command{gawk} ignores @code{fd} and returns the existing file. It is +the caller's responsibility to notice that neither the @code{fd} in +the returned @code{awk_input_buf_t} nor the @code{fd} in the returned +@code{awk_output_buf_t} matches the requested value. + +Note that supplying a file descriptor is currently @emph{not} supported +for pipes. However, supplying a file descriptor should work for input, +output, append, and two-way (coprocess) sockets. If @code{filetype} +is two-way, @command{gawk} assumes that it is a socket! Note that in +the two-way case, the input and output file descriptors may differ. +To check for success, you must check whether either matches. +@end table + +It is anticipated that this API function will be used to implement I/O +multiplexing and a socket library. + @node Extension API Variables @subsection API Variables @@ -35157,18 +35299,21 @@ As of this writing, there are seven extensions: GD graphics library extension @item +MPFR library extension +(this provides access to a number of MPFR functions that @command{gawk}'s +native MPFR support does not) + +@item PDF extension @item PostgreSQL extension @item -MPFR library extension -(this provides access to a number of MPFR functions that @command{gawk}'s -native MPFR support does not) +Redis extension @item -Redis extension +Select extension @item XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} @@ -35352,6 +35497,24 @@ Add functions to implement system calls such as @code{chown()}, @code{chmod()}, and @code{umask()} to the file operations extension presented in @ref{Internal File Ops}. +@c Idea from comp.lang.awk, February 2015 +@item +Write an input parser that prints a prompt if the input is +a from a ``terminal'' device. You can use the @code{isatty()} +function to tell if the input file is a terminal. (Hint: this function +is usually expensive to call; try to call it just once.) +The content of the prompt should come from a variable settable +by @command{awk}-level code. +You can write the prompt to stanard error. However, +for best results, open a new file descriptor (or file pointer) +on @file{/dev/tty} and print the prompt there, in case standard +error has been redirected. + +Why is standard error a better +choice than standard output for writing the prompt? +Which reading mechanism should you replace, the one to get +a record, or the one to read raw bytes? + @item (Hard.) How would you provide namespaces in @command{gawk}, so that the diff --git a/doc/gawktexi.in b/doc/gawktexi.in index 88e854a5..4e2b67d7 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -599,6 +599,7 @@ particular records in a file and perform operations upon them. @code{getline}. * Getline Summary:: Summary of @code{getline} Variants. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -940,6 +941,7 @@ particular records in a file and perform operations upon them. * Array Functions:: Functions for working with arrays. * Flattening Arrays:: How to flatten arrays. * Creating Arrays:: How to create and populate arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension Versioning:: API Version information. * Extension API Informational Variables:: Variables providing information about @@ -6111,6 +6113,7 @@ used with it do not have to be named on the @command{awk} command line * Getline:: Reading files under explicit program control using the @code{getline} function. * Read Timeout:: Reading input with a timeout. +* Retrying Input:: Retrying input after certain errors. * Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. @@ -7713,6 +7716,13 @@ a record, such as a file that cannot be opened, then @code{getline} returns @minus{}1. In this case, @command{gawk} sets the variable @code{ERRNO} to a string describing the error that occurred. +If @code{ERRNO} indicates that the I/O operation may be +retried, and @code{PROCINFO["@var{input}", "RETRY"]} is set, +then @code{getline} returns @minus{}2 +instead of @minus{}1, and further calls to @code{getline} +may be attemped. @DBXREF{Retrying Input} for further information about +this feature. + In the following examples, @var{command} stands for a string value that represents a shell command. @@ -8367,7 +8377,8 @@ on a per-command or per-connection basis. the attempt to read from the underlying device may succeed in a later attempt. This is a limitation, and it also means that you cannot use this to multiplex input from -two or more sources. +two or more sources. @DBXREF{Retrying Input} for a way to enable +later I/O attempts to succeed. Assigning a timeout value prevents read operations from blocking indefinitely. But bear in mind that there are other ways @@ -8377,6 +8388,36 @@ a connection before it can start reading any data, or the attempt to open a FIFO special file for reading can block indefinitely until some other process opens it for writing. +@node Retrying Input +@section Retrying Reads After Certain Input Errors +@cindex retrying input + +@cindex differences in @command{awk} and @command{gawk}, retrying input +This @value{SECTION} describes a feature that is specific to @command{gawk}. + +When @command{gawk} encounters an error while reading input, by +default @code{getline} returns @minus{}1, and subsequent attempts to +read from that file result in an end-of-file indication. However, you +may optionally instruct @command{gawk} to allow I/O to be retried when +certain errors are encountered by setting a special element in +the @code{PROCINFO} array (@pxref{Auto-set}): + +@example +PROCINFO["@var{input_name}", "RETRY"] = 1 +@end example + +When this element exists, @command{gawk} checks the value of the system +(C language) +@code{errno} variable when an I/O error occurs. If @code{errno} indicates +a subsequent I/O attempt may succeed, @code{getline} instead returns +@minus{}2 and +further calls to @code{getline} may succeed. This applies to the @code{errno} +values @code{EAGAIN}, @code{EWOULDBLOCK}, @code{EINTR}, or @code{ETIMEDOUT}. + +This feature is useful in conjunction with +@code{PROCINFO["@var{input_name}", "READ_TIMEOUT"]} or situations where a file +descriptor has been configured to behave in a non-blocking fashion. + @node Command-line directories @section Directories on the Command Line @cindex differences in @command{awk} and @command{gawk}, command-line directories @@ -14256,6 +14297,11 @@ value to be meaningful when an I/O operation returns a failure value, such as @code{getline} returning @minus{}1. You are, of course, free to clear it yourself before doing an I/O operation. +If the value of @code{ERRNO} corresponds to a system error in the C +@code{errno} variable, then @code{PROCINFO["errno"]} will be set to the value +of @code{errno}. For non-system errors, @code{PROCINFO["errno"]} will +be zero. + @cindex @code{FILENAME} variable @cindex dark corner, @code{FILENAME} variable @item @code{FILENAME} @@ -14324,6 +14370,10 @@ are guaranteed to be available: @item PROCINFO["egid"] The value of the @code{getegid()} system call. +@item PROCINFO["errno"] +The value of the C @code{errno} variable when @code{ERRNO} is set to +the associated error message. + @item PROCINFO["euid"] @cindex effective user ID of @command{gawk} user The value of the @code{geteuid()} system call. @@ -14374,7 +14424,7 @@ while the program runs. The value of the @code{getgid()} system call. @item PROCINFO["pgrpid"] -@cindex process group idIDof @command{gawk} process +@cindex process group ID of @command{gawk} process The process group ID of the current process. @item PROCINFO["pid"] @@ -14426,7 +14476,7 @@ The version of the GNU MP library. The maximum precision supported by MPFR. @item PROCINFO["prec_min"] -@cindex minimum precision supported by MPFR library +@cindex minimum precision required by MPFR library The minimum precision required by MPFR. @end table @@ -14463,6 +14513,11 @@ open input file, pipe, or coprocess. @DBXREF{Read Timeout} for more information. @item +It may be used to indicate that input may be retried when it fails due to +certain errors. +@DBXREF{Retrying Input} for more information. + +@item It may be used to cause coprocesses to communicate over pseudo-ttys instead of through two-way pipes; this is discussed further in @ref{Two-way I/O}. @@ -16380,8 +16435,8 @@ function randint(n) @end example @noindent -The multiplication produces a random number greater than zero and less -than @code{n}. Using @code{int()}, this result is made into +The multiplication produces a random number greater than or equal to +zero and less than @code{n}. Using @code{int()}, this result is made into an integer between zero and @code{n} @minus{} 1, inclusive. The following example uses a similar function to produce random integers @@ -19572,10 +19627,23 @@ Remember that you must supply a leading @samp{@@} in front of an indirect functi Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function calls may also be used with built-in functions and with extension functions -(@pxref{Dynamic Extensions}). The only thing you cannot do is pass a regular -expression constant to a built-in function through an indirect function -call.@footnote{This may change in a future version; recheck the documentation that -comes with your version of @command{gawk} to see if it has.} +(@pxref{Dynamic Extensions}). There are some limitations when calling +built-in functions indirectly, as follows. + +@itemize @value{BULLET} +@item +You cannot pass a regular expression constant to a built-in function +through an indirect function call.@footnote{This may change in a future +version; recheck the documentation that comes with your version of +@command{gawk} to see if it has.} This applies to the @code{sub()}, +@code{gsub()}, @code{gensub()}, @code{match()}, @code{split()} and +@code{patsplit()} functions. + +@item +If calling @code{sub()} or @code{gsub()}, you may only pass two arguments, +since those functions are unusual in that they update their third argument. +This means that @code{$0} will be updated. +@end itemize @command{gawk} does its best to make indirect function calls efficient. For example, in the following case: @@ -30662,6 +30730,7 @@ This (rather large) @value{SECTION} describes the API in detail. * Symbol Table Access:: Functions for accessing global variables. * Array Manipulation:: Functions for working with arrays. +* Redirection API:: How to access and manipulate redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. @end menu @@ -30737,6 +30806,10 @@ Clearing an array @item Flattening an array for easy C-style looping over all its indices and elements @end itemize + +@item +Accessing and manipulating redirections. + @end itemize Some points about using the API: @@ -32707,6 +32780,75 @@ $ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk} (@DBXREF{Finding Extensions} for more information on the @env{AWKLIBPATH} environment variable.) +@node Redirection API +@subsection Accessing and Manipulating Redirections + +The following function allows extensions to access and manipulate redirections. + +@table @code +@item awk_bool_t get_file(const char *name, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t name_len, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *filetype, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int fd, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_input_buf_t **ibufp, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_output_buf_t **obufp); +Look up a file in @command{gawk}'s internal redirection table. +If @code{name} is @code{NULL} or @code{name_len} is zero, return +data for the currently open input file corresponding to @code{FILENAME}. +(This does not access the @code{filetype} argument, so that may be undefined). +If the file is not already open, attempt to open it. +The @code{filetype} argument must be zero-terminated and should be one of: + +@table @code +@item ">" +A file opened for output. + +@item ">>" +A file opened for append. + +@item "<" +A file opened for input. + +@item "|>" +A pipe opened for output. + +@item "|<" +A pipe opened for input. + +@item "|&" +A two-way coprocess. +@end table + +On error, return a @code{false} value. Otherwise, return +@code{true}, and return additional information about the redirection +in the @code{ibufp} and @code{obufp} pointers. For input +redirections, the @code{*ibufp} value should be non-@code{NULL}, +and @code{*obufp} should be @code{NULL}. For output redirections, +the @code{*obufp} value should be non-@code{NULL}, and @code{*ibufp} +should be @code{NULL}. For two-way coprocesses, both values should +be non-@code{NULL}. + +In the usual case, the extension is interested in @code{(*ibufp)->fd} +and/or @code{fileno((*obufp)->fp)}. If the file is not already +open, and the @code{fd} argument is non-negative, @command{gawk} +will use that file descriptor instead of opening the file in the +usual way. If @code{fd} is non-negative, but the file exists already, +@command{gawk} ignores @code{fd} and returns the existing file. It is +the caller's responsibility to notice that neither the @code{fd} in +the returned @code{awk_input_buf_t} nor the @code{fd} in the returned +@code{awk_output_buf_t} matches the requested value. + +Note that supplying a file descriptor is currently @emph{not} supported +for pipes. However, supplying a file descriptor should work for input, +output, append, and two-way (coprocess) sockets. If @code{filetype} +is two-way, @command{gawk} assumes that it is a socket! Note that in +the two-way case, the input and output file descriptors may differ. +To check for success, you must check whether either matches. +@end table + +It is anticipated that this API function will be used to implement I/O +multiplexing and a socket library. + @node Extension API Variables @subsection API Variables @@ -34248,18 +34390,21 @@ As of this writing, there are seven extensions: GD graphics library extension @item +MPFR library extension +(this provides access to a number of MPFR functions that @command{gawk}'s +native MPFR support does not) + +@item PDF extension @item PostgreSQL extension @item -MPFR library extension -(this provides access to a number of MPFR functions that @command{gawk}'s -native MPFR support does not) +Redis extension @item -Redis extension +Select extension @item XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} @@ -34443,6 +34588,24 @@ Add functions to implement system calls such as @code{chown()}, @code{chmod()}, and @code{umask()} to the file operations extension presented in @ref{Internal File Ops}. +@c Idea from comp.lang.awk, February 2015 +@item +Write an input parser that prints a prompt if the input is +a from a ``terminal'' device. You can use the @code{isatty()} +function to tell if the input file is a terminal. (Hint: this function +is usually expensive to call; try to call it just once.) +The content of the prompt should come from a variable settable +by @command{awk}-level code. +You can write the prompt to stanard error. However, +for best results, open a new file descriptor (or file pointer) +on @file{/dev/tty} and print the prompt there, in case standard +error has been redirected. + +Why is standard error a better +choice than standard output for writing the prompt? +Which reading mechanism should you replace, the one to get +a record, or the one to read raw bytes? + @item (Hard.) How would you provide namespaces in @command{gawk}, so that the @@ -25,7 +25,6 @@ #include "awk.h" -extern void after_beginfile(IOBUF **curfile); extern double pow(double x, double y); extern double modf(double x, double *yp); extern double fmod(double x, double y); @@ -1027,6 +1026,7 @@ update_ERRNO_int(int errcode) { char *cp; + update_PROCINFO_num("errno", errcode); if (errcode) { cp = strerror(errcode); cp = gettext(cp); @@ -1041,6 +1041,7 @@ update_ERRNO_int(int errcode) void update_ERRNO_string(const char *string) { + update_PROCINFO_num("errno", 0); unref(ERRNO_node->var_value); ERRNO_node->var_value = make_string(string, strlen(string)); } @@ -1050,6 +1051,7 @@ update_ERRNO_string(const char *string) void unset_ERRNO(void) { + update_PROCINFO_num("errno", 0); unref(ERRNO_node->var_value); ERRNO_node->var_value = dupnode(Nnull_string); } @@ -1182,7 +1184,7 @@ r_get_lhs(NODE *n, bool reference) /* r_get_field --- get the address of a field node */ -static inline NODE ** +NODE ** r_get_field(NODE *n, Func_ptr *assign, bool reference) { long field_num; diff --git a/extension/ChangeLog b/extension/ChangeLog index 5d8c7b8a..5d1651fd 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,7 @@ +2015-03-27 Arnold D. Robbins <arnold@skeeve.com> + + * testext.c: Move test for deferred variables here. + 2015-03-18 Arnold D. Robbins <arnold@skeeve.com> * configure: Updated to libtool 2.4.6. @@ -34,11 +38,79 @@ * testext.c (var_test): Adjust for PROCINFO now being there. +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.c (test_deferred): New function to help with testing + of deferred variable instantiation. + (do_get_file): Remove unused variable array. + (func_table): Add test_deferred. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.c (test_get_file): Fix error message. + (do_get_file): Implement new function providing low-level access + to the get_file API. + (func_table): Add "get_file" -> do_get_file. + (init_testext): If TESTEXT_QUIET has been set to a numeric value, + return quietly. + +2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.c (test_get_file): The get_file hook no longer takes a + typelen argument. + +2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Remove the select extension, since it will be part of gawkextlib. + * select.c, siglist.h: Deleted. + * Makefile.am (pkgextension_LTLIBRARIES): Remove select.la. + (select_la_SOURCES, select_la_LDFLAGS, select_la_LIBADD): Remove. + (EXTRA_DIST): Remove siglist.h. + * configure.ac (AC_CHECK_HEADERS): Remove signal.h. + (AC_CHECK_FUNCS): Remove fcntl, kill, sigaction, and sigprocmask. + +2014-12-14 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Remove the errno extension, since it is now part of gawkextlib. + * errno.c, errlist.h: Deleted. + * Makefile.am (pkgextension_LTLIBRARIES): Remove errno.la. + (errno_la_SOURCES, errno_la_LDFLAGS, errno_la_LIBADD): Remove. + (EXTRA_DIST): Remove errlist.h. + 2014-11-23 Arnold D. Robbins <arnold@skeeve.com> * inplace.c (do_inplace_begin): Jump through hoops to silence GCC warnings about return value of chown. +2014-11-09 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (do_input_fd): New function to return the input file + descriptor associated with a file/command. + (do_output_fd): New function to return the output file descriptor + associated with a file/command. + (func_table): Add new functions "input_fd" and "output_fd". + * testext.c (test_get_file): Do not use __func__, since it is a C99 + feature, and gawk does not assume C99. + +2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * errno.c (do_errno2name, do_name2errno): Remove unused variable 'str'. + * select.c (do_signal): Remove unused variable 'override'. + (grabfd): New helper function to map a gawk file to the appropriate + fd for use in the arguments to selectd. + (do_select): get_file has 3 new arguments and returns info about both + the input and output buf. + (do_set_non_blocking): Support changes to get_file API. + * testext.c (test_get_file): New test function to check that extension + file creation via the get_file API is working. + +2014-11-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (set_retry): New function to set PROCINFO[<name>, "RETRY"]. + (do_set_non_blocking): If called with a file name as opposed to a file + descriptor, call the set_retry function to configure PROCINFO to tell + io.c to retry I/O for temporary failures. + 2014-10-12 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (uninstall-so): Remove *.lib too, per suggestion @@ -210,6 +282,108 @@ * gawkdirfd.h (FAKE_FD_VALUE): Move definition up in the file to give clean compile on MinGW. +2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * configure.ac (AC_CHECK_FUNCS): Check for fcntl. + * select.c (set_non_blocking): Check that fcntl and O_NONBLOCK are + available. + +2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (signal_handler): On platforms lacking sigaction, reset + the signal handler each time a signal is trapped to protect in case + the system resets it to default. + +2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (signal_result): New function to set result string from + signal function and detect when we need to roll back. + (do_signal): Now takes an optional 3rd override argument. Instead + of returning -1 or 0, we now return information about the previously + installed signal handler: default, ignore, trap, or unknown. An + empty string is returned on error. If it is an unknown handler, + and override is not non-zero, we roll back the handler and return "". + +2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (set_non_blocking): Do not attempt F_SETFL if F_GETFL fails. + (do_set_non_blocking): Add support for case when called with a single + "" argument. + +2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (do_signal): If sigaction is unavailable, fall back to + signal and hope that it does the right thing. + +2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * configure.ac (AC_CHECK_FUNCS): Add kill and sigprocmask. + * select.c (get_signal_number): Change error messages since now may + be called by "kill" as well as "select_signal". + (do_signal): Add a lint warning if there are more than 2 args. + (do_kill): Add new function to send a signal. + (do_select): Support platforms where sigprocmask is not available. + There will be a race condition on such platforms, but that is not + easily avoided. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (do_select): Now that the API flatten_array call has been + patched to ensure that the index values are strings, we can remove + the code to check for the AWK_NUMBER case. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (do_select): Do not treat a numeric command value as a + file descriptor unless the command type is empty. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add errlist.h and siglist.h. + +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (set_non_blocking): New helper function to call fcntl. + (do_set_non_blocking): Add support for the case where there's a single + integer fd argument. + +2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (do_set_non_blocking): Implement new set_non_blocking + function. + (func_table): Add set_non_blocking. + +2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * errlist.h: New file containing a list of all the errno values I could + find. + * errno.c: Implement a new errno extension providing strerror, + errno2name, and name2errno. + * Makefile.am (pkgextension_LTLIBRARIES): Add errno.la. + (errno_la_SOURCES, errno_la_LDFLAGS, errno_la_LIBADD): Build new errno + extension. + * select.c (ext_version): Fix version string. + * siglist.h: Update to newest glibc version. + +2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * siglist.h: New file copied from glibc to provide a mapping between + signal number and name. + * select.c: Add a new "select_signal" function and provide support + for trapping signals. + (do_select): Add support for a 5th argument to contain an array + of returned signals. Improve the argument processing, and add + better warning messages. + +2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (pkgextension_LTLIBRARIES): Add select.la. + (select_la_SOURCES, select_la_LDFLAGS, select_la_LIBADD): Build new + select extension. + * configure.ac (AC_CHECK_HEADERS): Add signal.h. + (AC_CHECK_FUNCS): Add sigaction. + * select.c: Implement the new select extension. + 2013-06-10 Arnold D. Robbins <arnold@skeeve.com> * configure.ac (AC_HEADER_MAJOR): New macro added. diff --git a/extension/testext.c b/extension/testext.c index 4a1e7032..e2ddbe87 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -37,6 +37,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include "gawkapi.h" @@ -374,6 +375,84 @@ out: } /* + * 3/2015: This test is no longer strictly necessary, + * since PROCINFO is no longer a deferred variable. + * But we leave it in for safety, anyway. + */ +/* +BEGIN { + print "test_deferred returns", test_deferred() + print "" +} +*/ +static awk_value_t * +test_deferred(int nargs, awk_value_t *result) +{ + awk_value_t arr; + awk_value_t index, value; + const struct nval { + const char *name; + double val; + } seed[] = { + { "fubar", 9.0, }, + { "rumpus", -5.0, }, + }; + struct nval sysval[] = { + { "uid", getuid(), }, + { "api_major", GAWK_API_MAJOR_VERSION, }, + }; + size_t i; + + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 0) { + printf("test_deferred: nargs not right (%d should be 0)\n", nargs); + goto out; + } + + if (! sym_lookup("PROCINFO", AWK_ARRAY, & arr)) { + printf("test_deferred: %d: sym_lookup failed\n", __LINE__); + goto out; + } + + for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) { + make_const_string(seed[i].name, strlen(seed[i].name), & index); + make_number(seed[i].val, & value); + if (! set_array_element(arr.array_cookie, & index, & value)) { + printf("test_deferred: %d: set_array_element(%s) failed\n", __LINE__, seed[i].name); + goto out; + } + } + + /* test that it still contains the values we loaded */ + for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) { + make_const_string(seed[i].name, strlen(seed[i].name), & index); + make_null_string(& value); + if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) { + printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, seed[i].name); + goto out; + } + printf("%s = %g\n", seed[i].name, value.num_value); + } + + /* check a few automatically-supplied values */ + for (i = 0; i < sizeof(sysval)/sizeof(sysval[0]); i++) { + make_const_string(sysval[i].name, strlen(sysval[i].name), & index); + make_null_string(& value); + if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) { + printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, sysval[i].name); + goto out; + } + printf("%s matches %d\n", sysval[i].name, (value.num_value == sysval[i].val)); + } + + make_number(1.0, result); +out: + return result; +} + +/* BEGIN { for (i = 1; i <= 10; i++) test_array[i] = i + 2 @@ -710,6 +789,7 @@ BEGIN { ret = test_indirect_vars() # should get correct value of NR printf("test_indirect_var() return %d\n", ret) delete ARGV[1] + print "" } */ @@ -742,6 +822,124 @@ out: return result; } +/* +BEGIN { + outfile = "testexttmp.txt" + alias = ".test.alias" + print "line 1" > outfile + print "line 2" > outfile + print "line 3" > outfile + close(outfile) + ret = test_get_file(outfile, alias) + printf "test_get_file returned %d\n", ret + nr = 0 + while ((getline < alias) > 0) + printf "File [%s] nr [%s]: %s\n", alias, ++nr, $0 + close(alias) + system("rm " outfile) + print "" +} +*/ + +/* test_get_file --- test that we can create a file */ + +static awk_value_t * +test_get_file(int nargs, awk_value_t *result) +{ + awk_value_t filename, alias; + int fd; + const awk_input_buf_t *ibuf; + const awk_output_buf_t *obuf; + + if (nargs != 2) { + printf("%s: nargs not right (%d should be 2)\n", "test_get_file", nargs); + return make_number(-1.0, result); + } + + if (! get_argument(0, AWK_STRING, & filename)) { + printf("%s: cannot get first arg\n", "test_get_file"); + return make_number(-1.0, result); + } + if (! get_argument(1, AWK_STRING, & alias)) { + printf("%s: cannot get second arg\n", "test_get_file"); + return make_number(-1.0, result); + } + if ((fd = open(filename.str_value.str, O_RDONLY)) < 0) { + printf("%s: open(%s) failed\n", "test_get_file", filename.str_value.str); + return make_number(-1.0, result); + } + if (! get_file(alias.str_value.str, strlen(alias.str_value.str), "<", fd, &ibuf, &obuf)) { + printf("%s: get_file(%s) failed\n", "test_get_file", alias.str_value.str); + return make_number(-1.0, result); + } + if (! ibuf || ibuf->fd != fd) { + printf("%s: get_file(%s) returned fd %d instead of %d\n", "test_get_file", alias.str_value.str, ibuf ? ibuf->fd : -1, fd); + return make_number(-1.0, result); + } + return make_number(0.0, result); +} + +/* do_get_file --- provide access to get_file API */ + +static awk_value_t * +do_get_file(int nargs, awk_value_t *result) +{ + awk_value_t filename, filetype, fd, res; + const awk_input_buf_t *ibuf; + const awk_output_buf_t *obuf; + + if (nargs != 4) { + printf("%s: nargs not right (%d should be 4)\n", "get_file", nargs); + return make_number(-1.0, result); + } + + if (! get_argument(0, AWK_STRING, & filename)) { + printf("%s: cannot get first arg\n", "get_file"); + return make_number(-1.0, result); + } + if (! get_argument(1, AWK_STRING, & filetype)) { + printf("%s: cannot get second arg\n", "get_file"); + return make_number(-1.0, result); + } + if (! get_argument(2, AWK_NUMBER, & fd)) { + printf("%s: cannot get third arg\n", "get_file"); + return make_number(-1.0, result); + } + if (! get_argument(3, AWK_ARRAY, & res)) { + printf("%s: cannot get fourth arg\n", "get_file"); + return make_number(-1.0, result); + } + clear_array(res.array_cookie); + + if (! get_file(filename.str_value.str, strlen(filename.str_value.str), filetype.str_value.str, fd.num_value, &ibuf, &obuf)) { + printf("%s: get_file(%s, %s, %d) failed\n", "get_file", filename.str_value.str, filetype.str_value.str, (int)(fd.num_value)); + return make_number(0.0, result); + } + + if (ibuf) { + awk_value_t idx, val; + set_array_element(res.array_cookie, + make_const_string("input", 5, & idx), + make_number(ibuf->fd, & val)); + if (ibuf->name) + set_array_element(res.array_cookie, + make_const_string("input_name", 10, & idx), + make_const_string(ibuf->name, strlen(ibuf->name), & val)); + } + if (obuf) { + awk_value_t idx, val; + set_array_element(res.array_cookie, + make_const_string("output", 6, & idx), + make_number(obuf->fp ? fileno(obuf->fp) : -1, + & val)); + if (obuf->name) + set_array_element(res.array_cookie, + make_const_string("output_name", 11, & idx), + make_const_string(obuf->name, strlen(obuf->name), & val)); + } + return make_number(1.0, result); +} + /* fill_in_array --- fill in a new array */ static void @@ -829,6 +1027,7 @@ static awk_ext_func_t func_table[] = { { "dump_array_and_delete", dump_array_and_delete, 2 }, { "try_modify_environ", try_modify_environ, 0 }, { "var_test", var_test, 1 }, + { "test_deferred", test_deferred, 0 }, { "test_errno", test_errno, 0 }, { "test_array_size", test_array_size, 1 }, { "test_array_elem", test_array_elem, 2 }, @@ -837,6 +1036,8 @@ static awk_ext_func_t func_table[] = { { "test_scalar", test_scalar, 1 }, { "test_scalar_reserved", test_scalar_reserved, 0 }, { "test_indirect_vars", test_indirect_vars, 0 }, + { "test_get_file", test_get_file, 2 }, + { "get_file", do_get_file, 4 }, }; /* init_testext --- additional initialization function */ @@ -847,6 +1048,10 @@ static awk_bool_t init_testext(void) static const char message[] = "hello, world"; /* of course */ static const char message2[] = "i am a scalar"; + /* This is used by the getfile test */ + if (sym_lookup("TESTEXT_QUIET", AWK_NUMBER, & value)) + return awk_true; + /* add at_exit functions */ awk_atexit(at_exit0, NULL); awk_atexit(at_exit1, & data_for_1); @@ -25,6 +25,11 @@ #include "awk.h" +/* Declare some globals used by api_get_file: */ +extern IOBUF *curfile; +extern INSTRUCTION *main_beginfile; +extern int currule; + static awk_bool_t node_to_awk_value(NODE *node, awk_value_t *result, awk_valtype_t wanted); /* @@ -783,7 +788,6 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie, tmp = awk_value_to_node(index); aptr = assoc_lookup(array, tmp); - unref(tmp); unref(*aptr); elem = *aptr = awk_value_to_node(value); if (elem->type == Node_var_array) { @@ -791,6 +795,9 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie, elem->vname = estrdup(index->str_value.str, index->str_value.len); } + if (array->astore != NULL) + (*array->astore)(array, tmp); + unref(tmp); return awk_true; } @@ -1034,6 +1041,99 @@ api_release_value(awk_ext_id_t id, awk_value_cookie_t value) return awk_true; } +/* api_get_file --- return a handle to an existing or newly opened file */ + +static awk_bool_t +api_get_file(awk_ext_id_t id, const char *name, size_t namelen, const char *filetype, + int fd, const awk_input_buf_t **ibufp, const awk_output_buf_t **obufp) +{ + const struct redirect *f; + int flag; /* not used, sigh */ + enum redirval redirtype; + + if (name == NULL || namelen == 0) { + if (curfile == NULL) { + INSTRUCTION *pc; + int save_rule; + char *save_source; + + if (nextfile(& curfile, false) <= 0) + return awk_false; + + pc = main_beginfile; + /* save execution state */ + save_rule = currule; + save_source = source; + + for (;;) { + if (pc == NULL) + fatal(_("cannot find end of BEGINFILE rule")); + if (pc->opcode == Op_after_beginfile) + break; + pc = pc->nexti; + } + pc->opcode = Op_stop; + (void) (*interpret)(main_beginfile); + pc->opcode = Op_after_beginfile; + after_beginfile(& curfile); + /* restore execution state */ + currule = save_rule; + source = save_source; + } + *ibufp = &curfile->public; + *obufp = NULL; + + return awk_true; + } + + redirtype = redirect_none; + switch (filetype[0]) { + case '<': + if (filetype[1] == '\0') + redirtype = redirect_input; + break; + case '>': + switch (filetype[1]) { + case '\0': + redirtype = redirect_output; + break; + case '>': + if (filetype[2] == '\0') + redirtype = redirect_append; + break; + } + break; + case '|': + if (filetype[2] == '\0') { + switch (filetype[1]) { + case '>': + redirtype = redirect_pipe; + break; + case '<': + redirtype = redirect_pipein; + break; + case '&': + redirtype = redirect_twoway; + break; + } + } + break; + } + + if (redirtype == redirect_none) { + warning(_("cannot open unrecognized file type `%s' for `%s'"), + filetype, name); + return awk_false; + } + + if ((f = redirect_string(name, namelen, 0, redirtype, &flag, fd, false)) == NULL) + return awk_false; + + *ibufp = f->iop ? & f->iop->public : NULL; + *obufp = f->output.fp ? & f->output : NULL; + return awk_true; +} + /* * Register a version string for this extension with gawk. */ @@ -1119,6 +1219,9 @@ gawk_api_t api_impl = { calloc, realloc, free, + + /* Find/open a file */ + api_get_file, }; /* init_ext_api --- init the extension API */ @@ -263,7 +263,7 @@ typedef struct awk_two_way_processor { /* Current version of the API. */ enum { GAWK_API_MAJOR_VERSION = 1, - GAWK_API_MINOR_VERSION = 1 + GAWK_API_MINOR_VERSION = 2 }; /* A number of typedefs related to different types of values. */ @@ -504,7 +504,7 @@ typedef struct gawk_api { awk_value_t *result); /* - * Convert a paramter that was undefined into an array + * Convert a parameter that was undefined into an array * (provide call-by-reference for arrays). Returns false * if count is too big, or if the argument's type is * not undefined. @@ -674,6 +674,39 @@ typedef struct gawk_api { void *(*api_calloc)(size_t nmemb, size_t size); void *(*api_realloc)(void *ptr, size_t size); void (*api_free)(void *ptr); + + /* + * Look up a file. If the name is NULL or name_len is 0, it returns + * data for the currently open input file corresponding to FILENAME + * (and it will not access the filetype argument, so that may be + * undefined). + * If the file is not already open, it tries to open it. + * The "filetype" argument should be one of: + * ">", ">>", "<", "|>", "|<", and "|&" + * If the file is not already open, and the fd argument is non-negative, + * gawk will use that file descriptor instead of opening the file + * in the usual way. If the fd is non-negative, but the file exists + * already, gawk ignores the fd and returns the existing file. It is + * the caller's responsibility to notice that the fd in the returned + * awk_input_buf_t does not match the requested value. Note that + * supplying a file descriptor is currently NOT supported for pipes. + * It should work for input, output, append, and two-way (coprocess) + * sockets. If the filetype is two-way, we assume that it is a socket! + * Note that in the two-way case, the input and output file descriptors + * may differ. To check for success, one must check that either of + * them matches. + */ + awk_bool_t (*api_get_file)(awk_ext_id_t id, + const char *name, + size_t name_len, + const char *filetype, + int fd, + /* + * Return values (on success, one or both should + * be non-NULL): + */ + const awk_input_buf_t **ibufp, + const awk_output_buf_t **obufp); } gawk_api_t; #ifndef GAWK /* these are not for the gawk code itself! */ @@ -756,6 +789,9 @@ typedef struct gawk_api { #define release_value(value) \ (api->api_release_value(ext_id, value)) +#define get_file(name, namelen, filetype, fd, ibuf, obuf) \ + (api->api_get_file(ext_id, name, namelen, filetype, fd, ibuf, obuf)) + #define register_ext_version(version) \ (api->api_register_ext_version(ext_id, version)) diff --git a/interpret.h b/interpret.h index 3a9cab37..a11268de 100644 --- a/interpret.h +++ b/interpret.h @@ -1066,7 +1066,15 @@ match_re: assert(the_func != NULL); /* call it */ - r = the_func(arg_count); + if (the_func == (builtin_func_t) do_sub) + r = call_sub(t1->stptr, arg_count); + else if (the_func == do_match) + r = call_match(arg_count); + else if (the_func == do_split || the_func == do_patsplit) + r = call_split_func(t1->stptr, arg_count); + else + r = the_func(arg_count); + PUSH(r); break; } else if (f->type != Node_func) { @@ -1313,17 +1321,18 @@ match_re: fatal(_("`exit' cannot be called in the current context")); exiting = true; - t1 = POP_NUMBER(); - exit_val = (int) get_number_si(t1); - DEREF(t1); + if ((t1 = POP_NUMBER()) != Nnull_string) { + exit_val = (int) get_number_si(t1); #ifdef VMS - if (exit_val == 0) - exit_val = EXIT_SUCCESS; - else if (exit_val == 1) - exit_val = EXIT_FAILURE; - /* else - just pass anything else on through */ + if (exit_val == 0) + exit_val = EXIT_SUCCESS; + else if (exit_val == 1) + exit_val = EXIT_FAILURE; + /* else + just pass anything else on through */ #endif + } + DEREF(t1); if (currule == BEGINFILE || currule == ENDFILE) { @@ -271,7 +271,7 @@ static IOBUF *iop_alloc(int fd, const char *name, int errno_val); static IOBUF *iop_finish(IOBUF *iop); static int gawk_pclose(struct redirect *rp); static int str2mode(const char *mode); -static int two_way_open(const char *str, struct redirect *rp); +static int two_way_open(const char *str, struct redirect *rp, int extfd); static int pty_vs_pipe(const char *command); static void find_input_parser(IOBUF *iop); static bool find_output_wrapper(awk_output_buf_t *outbuf); @@ -595,7 +595,8 @@ inrec(IOBUF *iop, int *errcode) else cnt = get_a_record(& begin, iop, errcode); - if (cnt == EOF) { + /* Note that get_a_record may return -2 when I/O would block */ + if (cnt < 0) { retval = false; } else { INCREMENT_REC(NR); @@ -723,13 +724,13 @@ redflags2str(int flags) return genflags2str(flags, redtab); } -/* redirect --- Redirection for printf and print commands */ +/* redirect_string --- Redirection for printf and print commands, use string info */ struct redirect * -redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) +redirect_string(const char *str, size_t explen, bool not_string, + int redirtype, int *errflg, int extfd, bool failure_fatal) { struct redirect *rp; - char *str; int tflag = 0; int outflag = 0; const char *direction = "to"; @@ -778,18 +779,16 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) default: cant_happen(); } - if (do_lint && (redir_exp->flags & STRCUR) == 0) + if (do_lint && not_string) lintwarn(_("expression in `%s' redirection only has numeric value"), what); - redir_exp = force_string(redir_exp); - str = redir_exp->stptr; if (str == NULL || *str == '\0') fatal(_("expression for `%s' redirection has null string value"), what); - if (do_lint && (strncmp(str, "0", redir_exp->stlen) == 0 - || strncmp(str, "1", redir_exp->stlen) == 0)) + if (do_lint && (strncmp(str, "0", explen) == 0 + || strncmp(str, "1", explen) == 0)) lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what); @@ -827,8 +826,8 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) #endif /* PIPES_SIMULATED */ /* now check for a match */ - if (strlen(rp->value) == redir_exp->stlen - && memcmp(rp->value, str, redir_exp->stlen) == 0 + if (strlen(rp->value) == explen + && memcmp(rp->value, str, explen) == 0 && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag || (outflag != 0 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) { @@ -839,23 +838,25 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) if (do_lint && rpflag != newflag) lintwarn( _("unnecessary mixing of `>' and `>>' for file `%.*s'"), - (int) redir_exp->stlen, rp->value); + (int) explen, rp->value); break; } } if (rp == NULL) { + char *newstr; new_rp = true; if (save_rp != NULL) { rp = save_rp; efree(rp->value); } else emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect"); - emalloc(str, char *, redir_exp->stlen + 1, "redirect"); - memcpy(str, redir_exp->stptr, redir_exp->stlen); - str[redir_exp->stlen] = '\0'; - rp->value = str; + emalloc(newstr, char *, explen + 1, "redirect"); + memcpy(newstr, str, explen); + newstr[explen] = '\0'; + str = newstr; + rp->value = newstr; rp->flag = tflag; init_output_wrapper(& rp->output); rp->output.name = str; @@ -887,6 +888,10 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) mode = binmode("a"); break; case redirect_pipe: + if (extfd >= 0) { + warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd); + return NULL; + } /* synchronize output before new pipe */ (void) flush_io(); @@ -906,6 +911,10 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) rp->flag |= RED_NOBUF; break; case redirect_pipein: + if (extfd >= 0) { + warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd); + return NULL; + } direction = "from"; if (gawk_popen(str, rp) == NULL) fatal(_("can't open pipe `%s' for input (%s)"), @@ -913,7 +922,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) break; case redirect_input: direction = "from"; - fd = devopen(str, binmode("r")); + fd = (extfd >= 0) ? extfd : devopen(str, binmode("r")); if (fd == INVALID_HANDLE && errno == EISDIR) { *errflg = EISDIR; /* do not free rp, saving it for reuse (save_rp = rp) */ @@ -930,8 +939,14 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) } break; case redirect_twoway: +#ifndef HAVE_SOCKETS + if (extfd >= 0) { + warning(_("get_file socket creation not supported on this platform for `%s' with fd %d"), str, extfd); + return NULL; + } +#endif direction = "to/from"; - if (! two_way_open(str, rp)) { + if (! two_way_open(str, rp, extfd)) { if (! failure_fatal || is_non_fatal_redirect(str)) { *errflg = errno; /* do not free rp, saving it for reuse (save_rp = rp) */ @@ -948,7 +963,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) if (mode != NULL) { errno = 0; rp->output.mode = mode; - fd = devopen(str, mode); + fd = (extfd >= 0) ? extfd : devopen(str, mode); if (fd > INVALID_HANDLE) { if (fd == fileno(stdin)) @@ -1050,6 +1065,18 @@ redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) return rp; } +/* redirect --- Redirection for printf and print commands */ + +struct redirect * +redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) +{ + bool not_string = ((redir_exp->flags & STRCUR) == 0); + + redir_exp = force_string(redir_exp); + return redirect_string(redir_exp->stptr, redir_exp->stlen, not_string, + redirtype, errflg, -1, failure_fatal); +} + /* getredirect --- find the struct redirect for this file or pipe */ struct redirect * @@ -1758,16 +1785,16 @@ strictopen: /* two_way_open --- open a two way communications channel */ static int -two_way_open(const char *str, struct redirect *rp) +two_way_open(const char *str, struct redirect *rp, int extfd) { static bool no_ptys = false; #ifdef HAVE_SOCKETS /* case 1: socket */ - if (inetfile(str, NULL)) { + if (extfd >= 0 || inetfile(str, NULL)) { int fd, newfd; - fd = devopen(str, "rw"); + fd = (extfd >= 0) ? extfd : devopen(str, "rw"); if (fd == INVALID_HANDLE) return false; if ((BINMODE & BINMODE_OUTPUT) != 0) @@ -2227,17 +2254,43 @@ use_pipes: #ifndef PIPES_SIMULATED /* real pipes */ -/* wait_any --- wait for a child process, close associated pipe */ +/* + * wait_any --- if the argument pid is 0, wait for all child processes that + * have exited. We loop to make sure to reap all children that have exited to + * minimize the risk of running out of process slots. Since we don't process + * SIGCHLD, we do not immediately reap exited children. So when we get here, + * we want to reap any that have piled up. + * + * Note: on platforms that do not support waitpid with WNOHANG, when called with + * a zero argument, this function will hang until all children have exited. + * + * AJS, 2013-07-07: I do not see why we need to ignore signals during this + * function. This function just waits and updates the pid and status fields. + * I don't see why that should interfere with any signal handlers. But I am + * reluctant to remove this protection. So I changed to use sigprocmask to + * block signals instead to avoid interfering with installed signal handlers. + */ static int wait_any(int interesting) /* pid of interest, if any */ { - RETSIGTYPE (*hstat)(int), (*istat)(int), (*qstat)(int); int pid; int status = 0; struct redirect *redp; +#ifdef HAVE_SIGPROCMASK + sigset_t set, oldset; + + /* I have no idea why we are blocking signals during this function... */ + sigemptyset(& set); + sigaddset(& set, SIGINT); + sigaddset(& set, SIGHUP); + sigaddset(& set, SIGQUIT); + sigprocmask(SIG_BLOCK, & set, & oldset); +#else + RETSIGTYPE (*hstat)(int), (*istat)(int), (*qstat)(int); istat = signal(SIGINT, SIG_IGN); +#endif #ifdef __MINGW32__ if (interesting < 0) { status = -1; @@ -2253,11 +2306,22 @@ wait_any(int interesting) /* pid of interest, if any */ break; } } -#else +#else /* ! __MINGW32__ */ +#ifndef HAVE_SIGPROCMASK hstat = signal(SIGHUP, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); +#endif for (;;) { -# ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */ +# if defined(HAVE_WAITPID) && defined(WNOHANG) + /* + * N.B. If the caller wants status for a specific child process + * (i.e. interesting is non-zero), then we must hang until we + * get exit status for that child. + */ + if ((pid = waitpid(-1, & status, (interesting ? 0 : WNOHANG))) == 0) + /* No children have exited */ + break; +# elif defined(HAVE_SYS_WAIT_H) /* POSIX compatible sys/wait.h */ pid = wait(& status); # else pid = wait((union wait *) & status); @@ -2275,10 +2339,16 @@ wait_any(int interesting) /* pid of interest, if any */ if (pid == -1 && errno == ECHILD) break; } +#ifndef HAVE_SIGPROCMASK signal(SIGHUP, hstat); signal(SIGQUIT, qstat); #endif +#endif /* ! __MINGW32__ */ +#ifndef HAVE_SIGPROCMASK signal(SIGINT, istat); +#else + sigprocmask(SIG_SETMASK, & oldset, NULL); +#endif return status; } @@ -2499,7 +2569,7 @@ do_getline_redir(int into_variable, enum redirval redirtype) if (errcode != 0) { if (! do_traditional && (errcode != -1)) update_ERRNO_int(errcode); - return make_number((AWKNUM) -1.0); + return make_number((AWKNUM) cnt); } if (cnt == EOF) { @@ -2549,7 +2619,7 @@ do_getline(int into_variable, IOBUF *iop) update_ERRNO_int(errcode); if (into_variable) (void) POP_ADDRESS(); - return make_number((AWKNUM) -1.0); + return make_number((AWKNUM) cnt); } if (cnt == EOF) @@ -3442,10 +3512,45 @@ find_longest_terminator: return REC_OK; } +/* retryable --- return true if PROCINFO[<filename>, "RETRY"] exists */ + +static inline int +retryable(IOBUF *iop) +{ + return PROCINFO_node && in_PROCINFO(iop->public.name, "RETRY", NULL); +} + +/* errno_io_retry --- Does the I/O error indicate that the operation should be retried later? */ + +static inline int +errno_io_retry(void) +{ + switch (errno) { +#ifdef EAGAIN + case EAGAIN: +#endif +#ifdef EWOULDBLOCK +#if !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif +#endif +#ifdef EINTR + case EINTR: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#endif + return 1; + default: + return 0; + } +} + /* * get_a_record --- read a record from IOP into out, * return length of EOF, set RT. * Note that errcode is never NULL, and the caller initializes *errcode to 0. + * If I/O would block, return -2. */ static int @@ -3489,8 +3594,10 @@ get_a_record(char **out, /* pointer to pointer to data */ iop->flag |= IOP_AT_EOF; return EOF; } else if (iop->count == -1) { - iop->flag |= IOP_AT_EOF; *errcode = errno; + if (errno_io_retry() && retryable(iop)) + return -2; + iop->flag |= IOP_AT_EOF; return EOF; } else { iop->dataend = iop->buf + iop->count; @@ -3564,6 +3671,8 @@ get_a_record(char **out, /* pointer to pointer to data */ iop->count = iop->public.read_func(iop->public.fd, iop->dataend, amt_to_read); if (iop->count == -1) { *errcode = errno; + if (errno_io_retry() && retryable(iop)) + return -2; iop->flag |= IOP_AT_EOF; break; } else if (iop->count == 0) { diff --git a/test/ChangeLog b/test/ChangeLog index 5c74f3a4..02752ace 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,25 @@ +2015-03-31 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (indirectbuiltin): New test. + * indirectbuiltin.awk, indirectbuiltin.ok: New files. + +2015-03-27 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am: Remove defvar test and reference to files; test + code moved into extension/testext.c. + * defvar.awk, defvar.ok: Removed. + * testext.ok: Updated. + +2015-03-24 Arnold D. Robbins <arnold@skeeve.com> + + * id.ok: Update after fixes in code. + +2015-03-24 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add exitval3.awk and exitval3.ok. + (BASIC_TESTS): Add new test exitval3. + * exitval3.awk, exitval3.ok: New files. + 2015-03-17 Andrew J. Schorr <aschorr@telemetry-investments.com> * inplace1.ok, inplace2.ok, inplace3.ok: Update error message line @@ -113,6 +135,34 @@ * testext.ok: Adjust for code changes. +2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add defvar.awk and defvar.ok. + (SHLIB_TESTS): Add defvar. + (defvar): New test. + * defvar.awk, defvar.ok: New files. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add getfile.awk and getfile.ok. + (SHLIB_TESTS): Add getfile. + (getfile): New test. + * getfile.awk, getfile.ok: New files. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add timeout.awk and timeout.ok. + (BASIC_TESTS): Remove errno. + (GAWK_EXT_TESTS): Add errno and timeout. + * timeout.awk, timeout.ok: New files. + +2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add errno.awk, errno.in, and errno.ok. + (BASIC_TESTS): Add errno. + (errno): New test. + * errno.awk, errno.in, errno.ok: New files. + 2014-12-24 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (badbuild): New test. @@ -147,6 +197,10 @@ * mbprintf4.awk: Add record and line number for debugging. * mpprint4.ok: Adjust. +2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.ok: Add results from new test_get_file test. + 2014-11-02 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (profile7): New test. diff --git a/test/Makefile.am b/test/Makefile.am index d2cd0ddd..b45eaf95 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -212,6 +212,9 @@ EXTRA_DIST = \ dynlj.ok \ eofsplit.awk \ eofsplit.ok \ + errno.awk \ + errno.in \ + errno.ok \ exit.ok \ exit.sh \ exit2.awk \ @@ -221,6 +224,8 @@ EXTRA_DIST = \ exitval2.awk \ exitval2.ok \ exitval2.w32 \ + exitval3.awk \ + exitval3.ok \ fcall_exit.awk \ fcall_exit.ok \ fcall_exit2.awk \ @@ -340,6 +345,8 @@ EXTRA_DIST = \ gensub.ok \ gensub2.awk \ gensub2.ok \ + getfile.awk \ + getfile.ok \ getline.awk \ getline.in \ getline.ok \ @@ -429,6 +436,8 @@ EXTRA_DIST = \ include.awk \ include.ok \ include2.ok \ + indirectbuiltin.awk \ + indirectbuiltin.ok \ indirectcall.awk \ indirectcall.in \ indirectcall.ok \ @@ -948,6 +957,8 @@ EXTRA_DIST = \ testext.ok \ time.awk \ time.ok \ + timeout.awk \ + timeout.ok \ tradanch.awk \ tradanch.in \ tradanch.ok \ @@ -1011,7 +1022,7 @@ BASIC_TESTS = \ callparam childin clobber closebad clsflnam compare compare2 concat1 concat2 \ concat3 concat4 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ - eofsplit exit2 exitval1 exitval2 \ + eofsplit exit2 exitval1 exitval2 exitval3 \ fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \ fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsrs fsspcoln \ fstabplus funsemnl funsmnam funstack \ @@ -1047,13 +1058,13 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \ backw badargs beginfile1 beginfile2 binmode1 charasbytes \ - colonwarn clos1way crlf dbugeval delsub devfd devfd1 devfd2 dumpvars exit \ + colonwarn clos1way crlf dbugeval delsub devfd devfd1 devfd2 dumpvars errno exit \ fieldwdth fpat1 fpat2 fpat3 fpat4 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectcall indirectcall2 \ + include include2 indirectbuiltin indirectcall indirectcall2 \ lint lintold lintwarn \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ @@ -1065,7 +1076,8 @@ GAWK_EXT_TESTS = \ rsstart2 rsstart3 rstest6 shadow sortfor sortu split_after_fpat \ splitarg4 strftime \ strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ - symtab7 symtab8 symtab9 + symtab7 symtab8 symtab9 \ + timeout EXTRA_TESTS = inftest regtest @@ -1082,7 +1094,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 inplace1 inplace2 inplace3 \ + fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time # List of the tests which should be run with --lint option: @@ -1341,6 +1353,11 @@ devfd:: @$(AWK) 1 /dev/fd/4 /dev/fd/5 4<"$(srcdir)"/devfd.in4 5<"$(srcdir)"/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +errno: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fflush:: @echo $@ @"$(srcdir)"/fflush.sh >_$@ @@ -1934,6 +1951,11 @@ testext:: @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk +getfile: + @echo $@ + @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + readdir: @if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $$NF }'`" = nfs ]; then \ echo This test may fail on GNU/Linux systems when run on an NFS filesystem.; \ diff --git a/test/Makefile.in b/test/Makefile.in index cf8093b8..8053df5c 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -469,6 +469,9 @@ EXTRA_DIST = \ dynlj.ok \ eofsplit.awk \ eofsplit.ok \ + errno.awk \ + errno.in \ + errno.ok \ exit.ok \ exit.sh \ exit2.awk \ @@ -478,6 +481,8 @@ EXTRA_DIST = \ exitval2.awk \ exitval2.ok \ exitval2.w32 \ + exitval3.awk \ + exitval3.ok \ fcall_exit.awk \ fcall_exit.ok \ fcall_exit2.awk \ @@ -597,6 +602,8 @@ EXTRA_DIST = \ gensub.ok \ gensub2.awk \ gensub2.ok \ + getfile.awk \ + getfile.ok \ getline.awk \ getline.in \ getline.ok \ @@ -686,6 +693,8 @@ EXTRA_DIST = \ include.awk \ include.ok \ include2.ok \ + indirectbuiltin.awk \ + indirectbuiltin.ok \ indirectcall.awk \ indirectcall.in \ indirectcall.ok \ @@ -1205,6 +1214,8 @@ EXTRA_DIST = \ testext.ok \ time.awk \ time.ok \ + timeout.awk \ + timeout.ok \ tradanch.awk \ tradanch.in \ tradanch.ok \ @@ -1267,7 +1278,7 @@ BASIC_TESTS = \ callparam childin clobber closebad clsflnam compare compare2 concat1 concat2 \ concat3 concat4 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ - eofsplit exit2 exitval1 exitval2 \ + eofsplit exit2 exitval1 exitval2 exitval3 \ fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \ fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsrs fsspcoln \ fstabplus funsemnl funsmnam funstack \ @@ -1303,13 +1314,13 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \ backw badargs beginfile1 beginfile2 binmode1 charasbytes \ - colonwarn clos1way crlf dbugeval delsub devfd devfd1 devfd2 dumpvars exit \ + colonwarn clos1way crlf dbugeval delsub devfd devfd1 devfd2 dumpvars errno exit \ fieldwdth fpat1 fpat2 fpat3 fpat4 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectcall indirectcall2 \ + include include2 indirectbuiltin indirectcall indirectcall2 \ lint lintold lintwarn \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ @@ -1321,7 +1332,8 @@ GAWK_EXT_TESTS = \ rsstart2 rsstart3 rstest6 shadow sortfor sortu split_after_fpat \ splitarg4 strftime \ strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ - symtab7 symtab8 symtab9 + symtab7 symtab8 symtab9 \ + timeout EXTRA_TESTS = inftest regtest INET_TESTS = inetdayu inetdayt inetechu inetecht @@ -1335,7 +1347,7 @@ LOCALE_CHARSET_TESTS = \ mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc SHLIB_TESTS = \ - fnmatch filefuncs fork fork2 fts functab4 inplace1 inplace2 inplace3 \ + fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \ ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time @@ -1779,6 +1791,11 @@ devfd:: @$(AWK) 1 /dev/fd/4 /dev/fd/5 4<"$(srcdir)"/devfd.in4 5<"$(srcdir)"/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +errno: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fflush:: @echo $@ @"$(srcdir)"/fflush.sh >_$@ @@ -2371,6 +2388,11 @@ testext:: @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk +getfile: + @echo $@ + @$(AWK) -v TESTEXT_QUIET=1 -ltestext -f $(srcdir)/$@.awk $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + readdir: @if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $$NF }'`" = nfs ]; then \ echo This test may fail on GNU/Linux systems when run on an NFS filesystem.; \ @@ -2730,6 +2752,11 @@ exitval2: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +exitval3: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fcall_exit: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3607,6 +3634,11 @@ include: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +indirectbuiltin: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + indirectcall: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3797,6 +3829,11 @@ symtab7: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +timeout: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + double1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 5011fb1f..219d592d 100644 --- a/test/Maketests +++ b/test/Maketests @@ -230,6 +230,11 @@ exitval2: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +exitval3: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + fcall_exit: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1107,6 +1112,11 @@ include: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +indirectbuiltin: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + indirectcall: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1297,6 +1307,11 @@ symtab7: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +timeout: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + double1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/errno.awk b/test/errno.awk new file mode 100644 index 00000000..bcb77614 --- /dev/null +++ b/test/errno.awk @@ -0,0 +1,10 @@ +BEGIN { + # check that PROCINFO["errno"] is working properly + getline + if (close(FILENAME)) { + print "Error `" ERRNO "' closing input file" + print "errno =", PROCINFO["errno"] + } + getline < (FILENAME "/bogus") + print (PROCINFO["errno"] > 0), ERRNO +} diff --git a/test/errno.in b/test/errno.in new file mode 100644 index 00000000..a92d664b --- /dev/null +++ b/test/errno.in @@ -0,0 +1,3 @@ +line 1 +line 2 +line 3 diff --git a/test/errno.ok b/test/errno.ok new file mode 100644 index 00000000..181afdaf --- /dev/null +++ b/test/errno.ok @@ -0,0 +1,3 @@ +Error `close of redirection that was never opened' closing input file +errno = 0 +1 Not a directory diff --git a/test/exitval3.awk b/test/exitval3.awk new file mode 100644 index 00000000..33e8c433 --- /dev/null +++ b/test/exitval3.awk @@ -0,0 +1,2 @@ +BEGIN { exit 42 } +END { exit } diff --git a/test/exitval3.ok b/test/exitval3.ok new file mode 100644 index 00000000..20f64b8c --- /dev/null +++ b/test/exitval3.ok @@ -0,0 +1 @@ +EXIT CODE: 42 diff --git a/test/getfile.awk b/test/getfile.awk new file mode 100644 index 00000000..6ee783f6 --- /dev/null +++ b/test/getfile.awk @@ -0,0 +1,35 @@ +function basename(x) { + return gensub(/^.*\//, "", 1, x) +} + +BEGIN { + print "BEGIN" + + cmd = "echo hello; echo goodbye" + rc = get_file(cmd, "<<", -1, res) + print "expected error result", rc, ERRNO + print "get_file returned", get_file(cmd, "|<", -1, res) + print "input_name", basename(res["input_name"]) + print (cmd | getline x) + print x + + # check that calling get_file on "" triggers the BEGINFILE rule + print "get_file returned", get_file("", "", -1, res) + print "input_name", basename(res["input_name"]) + print "end BEGIN" +} + +BEGINFILE { + printf "BEGINFILE (%s) ERRNO (%s)\n", basename(FILENAME), ERRNO +} + +ENDFILE { + printf "ENDFILE (%s) ERRNO (%s)\n", basename(FILENAME), ERRNO +} + +END { + print "END" + print (cmd | getline x) + print x + print close(cmd) +} diff --git a/test/getfile.ok b/test/getfile.ok new file mode 100644 index 00000000..92c915f2 --- /dev/null +++ b/test/getfile.ok @@ -0,0 +1,17 @@ +BEGIN +gawk: ./getfile.awk:9: warning: cannot open unrecognized file type `<<' for `echo hello; echo goodbye' +get_file: get_file(echo hello; echo goodbye, <<, -1) failed +expected error result 0 +get_file returned 1 +input_name echo hello; echo goodbye +1 +hello +BEGINFILE (getfile.awk) ERRNO () +get_file returned 1 +input_name getfile.awk +end BEGIN +ENDFILE (getfile.awk) ERRNO () +END +1 +goodbye +0 @@ -14,6 +14,7 @@ sprintf -> builtin ROUNDMODE -> scalar strftime -> builtin systime -> builtin +length -> builtin and -> builtin srand -> builtin FNR -> scalar diff --git a/test/indirectbuiltin.awk b/test/indirectbuiltin.awk new file mode 100644 index 00000000..4d5291d2 --- /dev/null +++ b/test/indirectbuiltin.awk @@ -0,0 +1,371 @@ +function print_result(category, fname, builtin_result, indirect_result) +{ + if (builtin_result == indirect_result) + printf("%s: %s: pass\n", category, fname) + else { + printf("%s: %s: fail: builtin: %s \tindirect: %s\n", category, fname, + builtin_result, indirect_result) + exit 1 + } +} + + +BEGIN { +# math functions + + fun = "and" + b1 = and(0x11, 0x01) + i1 = @fun(0x11, 0x01) + print_result("math", fun, b1, i1) + + fun = "atan2" + b1 = atan2(-1, 0) + i1 = @fun(-1, 0) + print_result("math", fun, b1, i1) + + fun = "compl" + b1 = compl(0x1111) + i1 = @fun(0x1111) + print_result("math", fun, b1, i1) + + fun = "cos" + b1 = cos(3.1415927 / 4) + i1 = @fun(3.1415927 / 4) + print_result("math", fun, b1, i1) + + fun = "exp" + b1 = exp(2) + i1 = @fun(2) + print_result("math", fun, b1, i1) + + fun = "int" + b1 = int(3.1415927) + i1 = @fun(3.1415927) + print_result("math", fun, b1, i1) + + fun = "log" + b1 = log(10) + i1 = @fun(10) + print_result("math", fun, b1, i1) + + fun = "lshift" + b1 = lshift(1, 2) + i1 = @fun(1, 2) + print_result("math", fun, b1, i1) + + fun = "or" + b1 = or(0x10, 0x01) + i1 = @fun(0x10, 0x01) + print_result("math", fun, b1, i1) + + fun = "rand" + srand(1) + b1 = rand(); + srand(1) + i1 = @fun() + print_result("math", fun, b1, i1) + + fun = "rshift" + b1 = rshift(0x10, 1) + i1 = @fun(0x10, 1) + print_result("math", fun, b1, i1) + + fun = "sin" + b1 = sin(3.1415927 / 4) + i1 = @fun(3.1415927 / 4) + print_result("math", fun, b1, i1) + + fun = "sqrt" + b1 = sqrt(2) + i1 = @fun(2) + print_result("math", fun, b1, i1) + + srand() + fun = "srand" + b1 = srand() + i1 = @fun() + print_result("math", fun, b1, i1) + + fun = "xor" + b1 = xor(0x11, 0x01) + i1 = @fun(0x11, 0x01) + print_result("math", fun, b1, i1) + +# string functions + + fun = "gensub" + b1 = gensub("f", "q", "g", "ff11bb") + i1 = @fun("f", "q", "g", "ff11bb") + print_result("string", fun, b1, i1) + + fun = "gsub" + $0 = "ff11bb" + b1 = gsub("f", "q") + b2 = $0 + $0 = "ff11bb" + i1 = @fun("f", "q") + i2 = $0 + print_result("string", fun, b1, i1) + if (b2 != i2) { + printf("string: %s: fail: $0 (%s) != $0 (%s)\n", + fun, b2, i2) + exit 1 + } + + fun = "index" + b1 = index("hi, how are you", "how") + i1 = @fun("hi, how are you", "how") + print_result("string", fun, b1, i1) + + fun = "dcgettext" + b1 = dcgettext("hello, world") + i1 = @fun("hello, world") + print_result("string", fun, b1, i1) + + fun = "dcngettext" + b1 = dcngettext("hello, world", "howdy", 2) + i1 = @fun("hello, world", "howdy", 2) + print_result("string", fun, b1, i1) + + fun = "length" + b1 = length("hi, how are you") + i1 = @fun("hi, how are you") + print_result("string", fun, b1, i1) + + fun = "sprintf" + b1 = sprintf("%s world", "hello") + i1 = @fun("%s world", "hello") + print_result("string", fun, b1, i1) + + fun = "strtonum" + b1 = strtonum("0xdeadbeef") + i1 = @fun("0xdeadbeef") + print_result("string", fun, b1, i1) + + fun = "sub" + $0 = "ff11bb" + b1 = sub("f", "q") + b2 = $0 + $0 = "ff11bb" + i1 = @fun("f", "q") + i2 = $0 + print_result("string", fun, b1, i1) + if (b2 != i2) { + printf("string: %s: fail: $0 (%s) != $0 (%s)\n", + fun, b2, i2) + exit 1 + } + + fun = "substr" + b1 = substr("0xdeadbeef", 7, 4) + i1 = @fun("0xdeadbeef", 7, 4) + print_result("string", fun, b1, i1) + + fun = "tolower" + b1 = tolower("0xDeAdBeEf") + i1 = @fun("0xDeAdBeEf") + print_result("string", fun, b1, i1) + + fun = "toupper" + b1 = toupper("0xDeAdBeEf") + i1 = @fun("0xDeAdBeEf") + print_result("string", fun, b1, i1) + +# time functions + + fun = "mktime" + b1 = mktime("1990 02 11 12 00 00") + i1 = @fun("1990 02 11 12 00 00") + print_result("time", fun, b1, i1) + + then = b1 + fun = "strftime" + b1 = strftime(PROCINFO["strftime"], then) + i1 = @fun(PROCINFO["strftime"], then) + print_result("time", fun, b1, i1) + + fun = "systime" + b1 = systime() + i1 = @fun() + print_result("time", fun, b1, i1) + +# regexp functions + + fun = "match" + b1 = match("o+", "fooob") + rstart = RSTART + rlength = RLENGTH + i1 = @fun("o+", "fooob") + print_result("regexp", fun, b1, i1) + if (rstart != RSTART) { + printf("match: failure: biRSTART (%d) != iRSTART (%d)\n", + rstart, RSTART) + exit 1 + } + if (rlength != RLENGTH) { + printf("match: failure: biRLENGTH (%d) != iRLENGTH (%d)\n", + rlength, RLENGTH) + exit 1 + } + + ############## start patsplit ############## + fun = "patsplit" + delete data + delete data2 + delete seps + delete seps2 + b1 = patsplit("a:b:c:d", data, ":", seps) + i1 = @fun("a:b:c:d", data2, ":", seps2) + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("patsplit1a: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + for (i in seps) { + if ((! (i in seps2)) || seps[i] != seps2[i]) { + printf("patsplit1b: fail: builtin seps[%d] (%s) != indirect seps[%d] (%s)\n", + i, seps[i], i, seps2[i]) + exit 1 + } + } + + fun = "patsplit" + delete data + delete data2 + b1 = patsplit("a:b:c:d", data, ":") + i1 = @fun("a:b:c:d", data2, ":") + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("patsplit2: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + + fun = "patsplit" + delete data + delete data2 + FPAT = "[a-z]+" + b1 = patsplit("a b c d", data) + i1 = @fun("a b c d", data2) + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("patsplit3: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + ############## end patsplit ############## + + ############## start split ############## + fun = "split" + delete data + delete data2 + delete seps + delete seps2 + b1 = split("a:b:c:d", data, ":", seps) + i1 = @fun("a:b:c:d", data2, ":", seps2) + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("split1a: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + for (i in seps) { + if ((! (i in seps2)) || seps[i] != seps2[i]) { + printf("split1b: fail: builtin seps[%d] (%s) != indirect seps[%d] (%s)\n", + i, seps[i], i, seps2[i]) + exit 1 + } + } + + fun = "split" + delete data + delete data2 + b1 = split("a:b:c:d", data, ":") + i1 = @fun("a:b:c:d", data2, ":") + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("split2: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + + fun = "split" + delete data + delete data2 + b1 = split("a b c d", data) + i1 = @fun("a b c d", data2) + print_result("regexp", fun, b1, i1) + for (i in data) { + if ((! (i in data2)) || data[i] != data2[i]) { + printf("split3: fail: builtin data[%d] (%s) != indirect data[%d] (%s)\n", + i, data[i], i, data2[i]) + exit 1 + } + } + ############## end split ############## + +# array functions + + split("z y x w v u t", data) + fun = "asort" + asort(data, newdata) + @fun(data, newdata2) + print_result("array", fun, b1, i1) + for (i in newdata) { + if (! (i in newdata2) || newdata[i] != newdata2[i]) { + print fun ": failed, index", i + exit + } + } + + for (i in data) + data2[data[i]] = i + + fun = "asorti" + asorti(data2, newdata) + @fun(data2, newdata2) + print_result("array", fun, b1, i1) + for (i in newdata) { + if (! (i in newdata2) || newdata[i] != newdata2[i]) { + print fun ": failed, index", i, "value", newdata[i], newdata2[i] + exit + } + } + + arr[1] = arr[2] = 42 + fun = "isarray" + b1 = isarray(arr) + i1 = @fun(arr) + print_result("array", fun, b1, i1) + +# i/o functions + + print("hi") > "x1.out" + print("hi") > "x2.out" + + fun = "fflush" + b1 = fflush("x1.out") + i1 = @fun("x2.out") + print_result("i/o", fun, b1, i1) + + fun = "close" + b1 = close("x1.out") + i1 = @fun("x2.out") + print_result("i/o", fun, b1, i1) + + fun = "system" + b1 = system("rm x1.out") + i1 = @fun("rm x2.out") + print_result("i/o", fun, b1, i1) +} diff --git a/test/indirectbuiltin.ok b/test/indirectbuiltin.ok new file mode 100644 index 00000000..312bbd76 --- /dev/null +++ b/test/indirectbuiltin.ok @@ -0,0 +1,43 @@ +math: and: pass +math: atan2: pass +math: compl: pass +math: cos: pass +math: exp: pass +math: int: pass +math: log: pass +math: lshift: pass +math: or: pass +math: rand: pass +math: rshift: pass +math: sin: pass +math: sqrt: pass +math: srand: pass +math: xor: pass +string: gensub: pass +string: gsub: pass +string: index: pass +string: dcgettext: pass +string: dcngettext: pass +string: length: pass +string: sprintf: pass +string: strtonum: pass +string: sub: pass +string: substr: pass +string: tolower: pass +string: toupper: pass +time: mktime: pass +time: strftime: pass +time: systime: pass +regexp: match: pass +regexp: patsplit: pass +regexp: patsplit: pass +regexp: patsplit: pass +regexp: split: pass +regexp: split: pass +regexp: split: pass +array: asort: pass +array: asorti: pass +array: isarray: pass +i/o: fflush: pass +i/o: close: pass +i/o: system: pass diff --git a/test/testext.ok b/test/testext.ok index a828ecb2..897a7336 100644 --- a/test/testext.ok +++ b/test/testext.ok @@ -23,6 +23,12 @@ var_test() returned 1, test_var = 42 test_errno() returned 1, ERRNO = No child processes +fubar = 9 +rumpus = -5 +uid matches 1 +api_major matches 1 +test_deferred returns 1 + length of test_array is 10, should be 10 test_array_size: incoming size is 10 test_array_size() returned 1, length is now 0 @@ -69,6 +75,12 @@ test_scalar_reserved: could not update new_value2 for ARGC - pass test_indirect_var: sym_lookup of NR passed test_indirect_var: value of NR is 3 test_indirect_var() return 1 + +test_get_file returned 0 +File [.test.alias] nr [1]: line 1 +File [.test.alias] nr [2]: line 2 +File [.test.alias] nr [3]: line 3 + answer_num = 42 message_string = hello, world new_array["hello"] = "world" diff --git a/test/timeout.awk b/test/timeout.awk new file mode 100644 index 00000000..ccf4537d --- /dev/null +++ b/test/timeout.awk @@ -0,0 +1,26 @@ +BEGIN { + cmd = "echo hello; sleep 1; echo goodbye" + + print "With timeouts" + PROCINFO[cmd, "READ_TIMEOUT"] = 300 + while ((rc = (cmd | getline x)) > 0) + print x + if (rc < 0) + print rc, (PROCINFO["errno"] != 0), (ERRNO != "") + print (close(cmd) != 0) + + PROCINFO[cmd, "RETRY"] + print "" + print "With timeouts and retries" + while (((rc = (cmd | getline x)) > 0) || (rc == -2)) { + if (rc > 0) { + print x + n = 0 + } + else + print ++n, "timed out; trying again" + } + if (rc < 0) + print rc, (PROCINFO["errno"] != 0), (ERRNO != "") + print (close(cmd) != 0) +} diff --git a/test/timeout.ok b/test/timeout.ok new file mode 100644 index 00000000..a388747b --- /dev/null +++ b/test/timeout.ok @@ -0,0 +1,12 @@ +With timeouts +hello +-1 1 1 +1 + +With timeouts and retries +hello +1 timed out; trying again +2 timed out; trying again +3 timed out; trying again +goodbye +0 |