aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2015-03-31 22:35:15 +0300
committerArnold D. Robbins <arnold@skeeve.com>2015-03-31 22:35:15 +0300
commitbbeeb351c73fb1ee4ff20c3774e0477e9e8a7513 (patch)
tree95f926cd9bf02578e9c860726a56441ac00e95b2
parenteb53fb0398911202d4361b869eefa6c1449ebec8 (diff)
parent902b25a40d5cc612dd7a0becb27a5a48afa49716 (diff)
downloadegawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.tar.gz
egawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.tar.bz2
egawk-bbeeb351c73fb1ee4ff20c3774e0477e9e8a7513.zip
Merge branch 'master' into feature/regex-type
-rw-r--r--ChangeLog228
-rw-r--r--NEWS6
-rw-r--r--awk.h9
-rw-r--r--awkgram.c24
-rw-r--r--awkgram.y24
-rw-r--r--builtin.c140
-rw-r--r--configh.in6
-rwxr-xr-xconfigure5
-rw-r--r--configure.ac5
-rw-r--r--doc/ChangeLog37
-rw-r--r--doc/gawk.147
-rw-r--r--doc/gawk.info1395
-rw-r--r--doc/gawk.texi189
-rw-r--r--doc/gawktexi.in189
-rw-r--r--eval.c6
-rw-r--r--extension/ChangeLog174
-rw-r--r--extension/testext.c205
-rw-r--r--gawkapi.c105
-rw-r--r--gawkapi.h40
-rw-r--r--interpret.h29
-rw-r--r--io.c169
-rw-r--r--test/ChangeLog54
-rw-r--r--test/Makefile.am32
-rw-r--r--test/Makefile.in47
-rw-r--r--test/Maketests15
-rw-r--r--test/errno.awk10
-rw-r--r--test/errno.in3
-rw-r--r--test/errno.ok3
-rw-r--r--test/exitval3.awk2
-rw-r--r--test/exitval3.ok1
-rw-r--r--test/getfile.awk35
-rw-r--r--test/getfile.ok17
-rw-r--r--test/id.ok1
-rw-r--r--test/indirectbuiltin.awk371
-rw-r--r--test/indirectbuiltin.ok43
-rw-r--r--test/testext.ok12
-rw-r--r--test/timeout.awk26
-rw-r--r--test/timeout.ok12
38 files changed, 2998 insertions, 718 deletions
diff --git a/ChangeLog b/ChangeLog
index ff18feab..790a47ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 1613cd8d..0c27c2c0 100644
--- a/NEWS
+++ b/NEWS
@@ -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
---------------------------
diff --git a/awk.h b/awk.h
index 1461ea3c..6d87aa2c 100644
--- a/awk.h
+++ b/awk.h
@@ -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);
diff --git a/awkgram.c b/awkgram.c
index e6eafe6f..0cb3d347 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -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);
}
diff --git a/awkgram.y b/awkgram.y
index 503186d8..d1fb4c3e 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -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);
}
diff --git a/builtin.c b/builtin.c
index 4a99ed6f..44011f12 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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. */
diff --git a/configh.in b/configh.in
index a3c411bb..f4309812 100644
--- a/configh.in
+++ b/configh.in
@@ -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
diff --git a/configure b/configure
index e425f55a..def8a041 100755
--- a/configure
+++ b/configure
@@ -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.
diff --git a/doc/gawk.1 b/doc/gawk.1
index 3d5d1812..45a4c9f2 100644
--- a/doc/gawk.1
+++ b/doc/gawk.1
@@ -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
diff --git a/eval.c b/eval.c
index bdf3d61c..7dd6a12b 100644
--- a/eval.c
+++ b/eval.c
@@ -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);
diff --git a/gawkapi.c b/gawkapi.c
index 3b495452..9d8c6f36 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -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 */
diff --git a/gawkapi.h b/gawkapi.h
index 7a58bd4a..3604e906 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -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) {
diff --git a/io.c b/io.c
index 55c5d3a5..cf9dd943 100644
--- a/io.c
+++ b/io.c
@@ -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
diff --git a/test/id.ok b/test/id.ok
index b2f2e922..b9bdf5bf 100644
--- a/test/id.ok
+++ b/test/id.ok
@@ -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