diff options
-rw-r--r-- | ChangeLog | 58 | ||||
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | awk.h | 7 | ||||
-rw-r--r-- | doc/ChangeLog | 14 | ||||
-rw-r--r-- | doc/gawk.info | 1309 | ||||
-rw-r--r-- | doc/gawk.texi | 223 | ||||
-rw-r--r-- | doc/gawktexi.in | 150 | ||||
-rw-r--r-- | ext.c | 2 | ||||
-rw-r--r-- | extension/ChangeLog | 43 | ||||
-rw-r--r-- | extension/filefuncs.c | 35 | ||||
-rw-r--r-- | extension/fnmatch.c | 11 | ||||
-rw-r--r-- | extension/fork.c | 24 | ||||
-rw-r--r-- | extension/inplace.c | 8 | ||||
-rw-r--r-- | extension/ordchr.c | 30 | ||||
-rw-r--r-- | extension/readdir.c | 2 | ||||
-rw-r--r-- | extension/readfile.c | 9 | ||||
-rw-r--r-- | extension/revoutput.c | 2 | ||||
-rw-r--r-- | extension/revtwoway.c | 2 | ||||
-rw-r--r-- | extension/rwarray.c | 14 | ||||
-rw-r--r-- | extension/rwarray0.c | 14 | ||||
-rw-r--r-- | extension/testext.c | 56 | ||||
-rw-r--r-- | extension/time.c | 14 | ||||
-rw-r--r-- | gawkapi.c | 2 | ||||
-rw-r--r-- | gawkapi.h | 36 | ||||
-rw-r--r-- | interpret.h | 21 |
25 files changed, 1183 insertions, 911 deletions
@@ -26,6 +26,49 @@ regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h, regexec.c, verify.h, xalloc.h: Moved to support. +2016-12-17 Arnold D. Robbins <arnold@skeeve.com> + + * gawkapi.h (api_add_ext_func): Add comment about point to + awk_ext_func_t not being const but gawk doesn't use it. + * * interpret.h (Op_ext_builtin): Simplify code, check only + if do_lint and ! f->suppress_lint and num_args > max_expected. + +2016-12-16 Arnold D. Robbins <arnold@skeeve.com> + + * gawkapi.h (awk_ext_func_t): Put max back before min. Restores + source compatibility, although there will be compile warnings + because of the 3rd argument for the C function being missing. + * interpret.h (Op_ext_builtin): Used size_t instead of int for + the various variables. Add a check that max expected > 0. + +2016-12-14 Arnold D. Robbins <arnold@skeeve.com> + + MAJOR BREAKING API CHANGE. + + * awk.h (INSTRUCTION): Update extension function pointer to + take 3rd argument of pointer to struct awk_ext_func. + * gawkapi.c (api_add_ext_func): Update third arg to not be const. + * gawkapi.h (awk_ext_func_t): Put min before max. Add suppress_lint + and data pointer. + [gawk_api_major_version]: Update to 2. + [gawk_api_minor_version]: Reset to 0. + (api_add_ext_func): Update third arg to not be const. + * interpret.h (Op_ext_symbol): Revise lint check. + +2016-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (INSTRUCTION): Replace min_required and max_expected + with a pointer to the extension functions awk_ext_func_t struct. + * ext.c (make_builtin): Store a pointer to the extension function + struct into the INSTRUCTION instead of the min and max. + * gawkapi.h (awk_ext_func): Use size_t instead of unsigned short. + Put min second, which preserves source code compatibility. + * interpret.h (Op_ext_builtin): Use the pointer for the info + directly. If lint and max_expected > 0 and args > max_expected + print a message and set max_expected to zero so we only print once + per function. Remove special case of both min and max being zero. + (Op_ext_func): Adjust creation of the data structures. + 2016-12-11 Arnold D. Robbins <arnold@skeeve.com> * dfa.c: Sync with GNULIB. @@ -81,6 +124,21 @@ (api_flatten_array): Now a wrapper around api_flatten_array_typed. (api_impl): Add new api_flatten_array_typed hook. +2016-12-06 Arnold D. Robbins <arnold@skeeve.com> + + Add minimum required and maximum expected number of arguments + to the API. + + * awk.h (INSTRUCTION): Add new members min_required and max_expected. + * ext.c (make_builtin): Store values from extension function struct + into the INSTRUCTION. + * gawkapi.h (awk_ext_func): Add min_required args. Make both it and + max_expected_args into unsigned short to match type in INSTRUCTION. + * interpret.h (Op_ext_builtin): Store min_required and max_expected + in instructions. Add checking code and lint checks. + (Op_ext_func): Copy min_required and max_expected from function info. + + 2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawkapi.h (r_make_string_type): New inline function to create strings @@ -90,6 +90,14 @@ Changes from 4.1.x to 4.2.0 22. Passing negative operands to any of the bitwise functions now produces a fatal error. +23. The C API has undergone changes that break binary compatibility with + the previous version. Thus the API version is now at 2.0. YOU WILL + NEED TO RECOMPILE YOUR EXTENSIONS to work with this version of gawk. + Source code compatibility remains intact, although you will get + compiler warnings if you do not revise your extensions. We strongly + recommend that you do so. Fortunately, the changes are fairly minor + and straightforward. + Changes from 4.1.3 to 4.1.4 --------------------------- @@ -767,7 +767,9 @@ typedef struct exp_instruction { NODE *dn; struct exp_instruction *di; NODE *(*fptr)(int); - awk_value_t *(*efptr)(int, awk_value_t *); + awk_value_t *(*efptr)(int num_actual_args, + awk_value_t *result, + struct awk_ext_func *finfo); long dl; char *name; } d; @@ -778,6 +780,7 @@ typedef struct exp_instruction { void (*aptr)(void); struct exp_instruction *xi; struct break_point *bpt; + awk_ext_func_t *exf; } x; short source_line; @@ -793,6 +796,8 @@ typedef struct exp_instruction { #define expr_count x.xl +#define c_func x.exf + #define target_continue d.di #define target_jmp d.di #define target_break x.xi diff --git a/doc/ChangeLog b/doc/ChangeLog index cafced8f..d3e974c7 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,17 @@ +2016-12-17 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Further API clarifications and edits, add a + section on backwards compatibility. + +2016-12-16 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Update description of awk_ext_func_t structure, + again. + +2016-12-14 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Update description of awk_ext_func_t structure. + 2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawktexi.in: Document strnum changes as relates to API. diff --git a/doc/gawk.info b/doc/gawk.info index 3bb2f352..67b52f5e 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -569,6 +569,7 @@ in (a) below. A copy of the license is included in the section entitled * Extension API Informational Variables:: Variables providing information about 'gawk''s invocation. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. * Finding Extensions:: How 'gawk' finds compiled extensions. * Extension Example:: Example C code for an extension. @@ -23439,6 +23440,7 @@ API in detail. redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. File: gawk.info, Node: Extension API Functions Introduction, Next: General Data Types, Up: Extension API Description @@ -23625,7 +23627,8 @@ use them. ' AWK_STRING,' ' AWK_ARRAY,' ' AWK_SCALAR, /* opaque access to a variable */' -' AWK_VALUE_COOKIE /* for updating a previously created value */' +' AWK_VALUE_COOKIE, /* for updating a previously created value */' +' AWK_REGEX' '} awk_valtype_t;' This 'enum' indicates the type of a value. It is used in the following 'struct'. @@ -23645,6 +23648,7 @@ use them. type. '#define str_value u.s' +'#define regex_value str_value' '#define num_value u.d' '#define array_cookie u.a' '#define scalar_cookie u.scl' @@ -23663,7 +23667,7 @@ use them. This is also discussed in a general fashion in the text following this list, and in more detail in *note Cached values::. - Scalar values in 'awk' are either numbers or strings. The + Scalar values in 'awk' are numbers, strings, or typed regexps. The 'awk_value_t' struct represents values. The 'val_type' member indicates what is in the 'union'. @@ -23672,6 +23676,12 @@ require more work. Because 'gawk' allows embedded NUL bytes in string values, a string must be represented as a pair containing a data pointer and length. This is the 'awk_string_t' type. + Typed regexp values (*note Strong Regexp Constants::) are not of much +use to extension functions. Extension functions can tell that they've +received them, and create them for scalar values. Otherwise, they can +examine the text of the regexp through 'regex_value.str' and +'regex_value.len'. + Identifiers (i.e., the names of global variables) can be associated with either scalar values or with arrays. In addition, 'gawk' provides true arrays of arrays, where any given array element can itself be an @@ -23831,6 +23841,11 @@ code would use them: This function simply creates a numeric value in the 'awk_value_t' variable pointed to by 'result'. +'static inline awk_value_t *' +'make_regex(const char *string, size_t length, awk_value_t *result);' + This function creates a strongly typed regexp value. 'string' is + the regular expression of length 'len'. + File: gawk.info, Node: Registration Functions, Next: Printing Messages, Prev: Constructor Functions, Up: Extension API Description @@ -23859,8 +23874,13 @@ Extension functions are described by the following record: typedef struct awk_ext_func { const char *name; - awk_value_t *(*function)(int num_actual_args, awk_value_t *result); - size_t max_expected_args; + awk_value_t *(*const function)(int num_actual_args, + awk_value_t *result, + struct awk_ext_func *finfo); + const size_t max_expected_args; + const size_t min_required_args; + awk_bool_t suppress_lint; + void *data; /* opaque pointer to any extra state */ } awk_ext_func_t; The fields are: @@ -23874,7 +23894,9 @@ Extension functions are described by the following record: which may be followed by any number of letters, digits, and underscores. Letter case in function names is significant. -'awk_value_t *(*function)(int num_actual_args, awk_value_t *result);' +'awk_value_t *(*const function)(int num_actual_args,' +' awk_value_t *result,' +' struct awk_ext_func *finfo);' This is a pointer to the C function that provides the extension's functionality. The function must fill in '*result' with either a number or a string. 'gawk' takes ownership of any string memory. @@ -23884,30 +23906,77 @@ Extension functions are described by the following record: The 'num_actual_args' argument tells the C function how many actual parameters were passed from the calling 'awk' code. + The 'finfo' parameter is a pointer to the 'awk_ext_func_t' for this + function. The called function may access data within it as + desired, or not. + The function must return the value of 'result'. This is for the convenience of the calling code inside 'gawk'. -'size_t max_expected_args;' +'const size_t max_expected_args;' This is the maximum number of arguments the function expects to - receive. Each extension function may decide what to do if the - number of arguments isn't what it expected. As with real 'awk' - functions, it is likely OK to ignore extra arguments. This value - does not affect actual program execution. + receive. If called with more arguments than this, and if lint + checking has been enabled, then 'gawk' prints a warning message. + For more information, see the entry for 'suppress_lint', later in + this list. - Extension functions should compare this value to the number of - actual arguments passed and possibly issue a lint warning if there - is an undesirable mismatch. Of course, if '--lint=fatal' is used, - this would cause the program to exit. +'const size_t min_required_args;' + This is the minimum number of arguments the function expects to + receive. If called with fewer arguments, 'gawk' prints a fatal + error message and exits. + +'awk_bool_t suppress_lint;' + This flag tells 'gawk' not to print a lint message if lint checking + has been enabled and if more arguments were supplied in the call + than expected. An extension function can tell if 'gawk' already + printed at least one such message by checking if 'num_actual_args > + finfo->max_expected_args'. If so, and the function does not want + more lint messages to be printed, it should set + 'finfo->suppress_lint' to 'awk_true'. + +'void *data;' + This is an opaque pointer to any data that an extension function + may wish to have available when called. Passing the + 'awk_ext_func_t' structure to the extension function, and having + this pointer available in it enable writing a single C or C++ + function that implements multiple 'awk'-level extension functions. Once you have a record representing your extension function, you register it with 'gawk' using this API function: -'awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func);' +'awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func);' This function returns true upon success, false otherwise. The 'namespace' parameter is currently not used; you should pass in an empty string ('""'). The 'func' pointer is the address of a 'struct' representing your function, as just described. + 'gawk' does not modify what 'func' points to, but the extension + function itself receives this pointer and can modify what it points + to, thus it is purposely not declared to be 'const'. + + The combination of 'min_required_args', 'max_expected_args', and +'suppress_lint' may be confusing. Here is how you should set things up. + +Any number of arguments is valid + Set 'min_required_args' and 'max_expected_args' to zero and set + 'suppress_lint' to 'awk_true'. + +A minimum number of arguments is required, no limit on maximum number of arguments + Set 'min_required_args' to the minimum required. Set + 'max_expected_args' to zero and set 'suppress_lint' to 'awk_true'. + +A minium number of arguments is required, a maximum number is expected + Set 'min_required_args' to the minimum required. Set + 'max_expected_args' to the maximum expected. Set 'suppress_lint' + to 'awk_false'. + +A minum number of arguments is required, and no more than a maximum is allowed + Set 'min_required_args' to the minimum required. Set + 'max_expected_args' to the maximum expected. Set 'suppress_lint' + to 'awk_false'. In your extension function, check that + 'num_actual_args' does not exceed 'f->max_expected_args'. If it + does, issue a fatal error message. + File: gawk.info, Node: Exit Callback Functions, Next: Extension Version String, Prev: Extension Functions, Up: Registration Functions @@ -24501,11 +24570,6 @@ termed a "symbol table". The functions are as follows: However, with the exception of the 'PROCINFO' array, an extension cannot change any of those variables. - CAUTION: It is possible for the lookup of 'PROCINFO' to fail. This - happens if the 'awk' program being run does not reference - 'PROCINFO'; in this case, 'gawk' doesn't bother to create the array - and populate it. - File: gawk.info, Node: Symbol table by cookie, Next: Cached values, Prev: Symbol table by name, Up: Symbol Table Access @@ -24529,8 +24593,9 @@ was discussed earlier, in *note General Data Types::. 'awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value);' Update the value associated with a scalar cookie. Return false if - the new value is not of type 'AWK_STRING' or 'AWK_NUMBER'. Here - too, the predefined variables may not be updated. + the new value is not of type 'AWK_STRING', 'AWK_REGEX', or + 'AWK_NUMBER'. Here too, the predefined variables may not be + updated. It is not obvious at first glance how to work with scalar cookies or what their raison d'e^tre really is. In theory, the 'sym_lookup()' and @@ -24644,8 +24709,8 @@ follows: 'awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result);' Create a cached string or numeric value from 'value' for efficient - later assignment. Only values of type 'AWK_NUMBER' and - 'AWK_STRING' are allowed. Any other type is rejected. + later assignment. Only values of type 'AWK_NUMBER', 'AWK_REGEX', + and 'AWK_STRING' are allowed. Any other type is rejected. 'AWK_UNDEFINED' could be allowed, but doing so would result in inferior performance. @@ -25297,10 +25362,10 @@ versions are available at compile time as C preprocessor defines to support conditional compilation, and as enum constants to facilitate debugging: -API Version C preprocessor define enum constant ---------------------------------------------------------------------------- -Major gawk_api_major_version GAWK_API_MAJOR_VERSION -Minor gawk_api_minor_version GAWK_API_MINOR_VERSION +API Version C Preprocessor Define enum constant +-------------------------------------------------------------------- +Major 'gawk_api_major_version' 'GAWK_API_MAJOR_VERSION' +Minor 'gawk_api_minor_version' 'GAWK_API_MINOR_VERSION' Table 16.2: gawk API version constants @@ -25317,10 +25382,10 @@ For this reason, the major and minor API versions of the running 'gawk' are included in the API 'struct' as read-only constant integers: 'api->major_version' - The major version of the running 'gawk' + The major version of the running 'gawk'. 'api->minor_version' - The minor version of the running 'gawk' + The minor version of the running 'gawk'. It is up to the extension to decide if there are API incompatibilities. Typically, a check like this is enough: @@ -25374,7 +25439,7 @@ predefined variable (*note Built-in Variables::). The others should not change during execution. -File: gawk.info, Node: Extension API Boilerplate, Prev: Extension API Variables, Up: Extension API Description +File: gawk.info, Node: Extension API Boilerplate, Next: Changes from API V1, Prev: Extension API Variables, Up: Extension API Description 16.4.14 Boilerplate Code ------------------------ @@ -25394,7 +25459,7 @@ the 'gawkapi.h' header file: static const char *ext_version = NULL; /* or ... = "some string" */ static awk_ext_func_t func_table[] = { - { "name", do_name, 1 }, + { "name", do_name, 1, 0, awk_false, NULL }, /* ... */ }; @@ -25475,6 +25540,22 @@ does the following: 'gawk'. +File: gawk.info, Node: Changes from API V1, Prev: Extension API Boilerplate, Up: Extension API Description + +16.4.15 Changes From Version 1 of the API +----------------------------------------- + +The current API is _not_ binary compatible with version 1 of the API. +You will have to recompile your extensions in order to use them with the +current version of 'gawk'. + + Fortunately, at the possible expense of some compile-time warnings, +the API remains source-code-compatible with the previous API. The major +differences are the additional members in the 'awk_ext_func_t' +structure, and the addition of the third argument to the C +implementation function. + + File: gawk.info, Node: Finding Extensions, Next: Extension Example, Prev: Extension API Description, Up: Dynamic Extensions 16.5 How 'gawk' Finds Extensions @@ -25691,24 +25772,20 @@ is a pointer to an 'awk_value_t' structure, usually named 'result': /* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * - do_chdir(int nargs, awk_value_t *result) + do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t newdir; int ret = -1; assert(result != NULL); - if (do_lint && nargs != 1) - lintwarn(ext_id, - _("chdir: called with incorrect number of arguments, " - "expecting 1")); - The 'newdir' variable represents the new directory to change to, which is retrieved with 'get_argument()'. Note that the first argument is numbered zero. If the argument is retrieved successfully, the function calls the -'chdir()' system call. If the 'chdir()' fails, 'ERRNO' is updated: +'chdir()' system call. Otherwise, if the 'chdir()' fails, it updates +'ERRNO': if (get_argument(0, AWK_STRING, & newdir)) { ret = chdir(newdir.str_value.str); @@ -25895,7 +25972,7 @@ declarations and argument checking: /* do_stat --- provide a stat() function for gawk */ static awk_value_t * - do_stat(int nargs, awk_value_t *result) + do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t file_param, array_param; char *name; @@ -25907,13 +25984,6 @@ declarations and argument checking: assert(result != NULL); - if (nargs != 2 && nargs != 3) { - if (do_lint) - lintwarn(ext_id, - _("stat: called with wrong number of arguments")); - return make_number(-1, result); - } - Then comes the actual work. First, the function gets the arguments. Next, it gets the information for the file. If the called function ('lstat()' or 'stat()') returns an error, the code sets 'ERRNO' and @@ -25970,11 +26040,9 @@ there is an initialization function: for loading each function into 'gawk': static awk_ext_func_t func_table[] = { - { "chdir", do_chdir, 1 }, - { "stat", do_stat, 2 }, - #ifndef __MINGW32__ - { "fts", do_fts, 3 }, - #endif + { "chdir", do_chdir, 1, 1, awk_false, NULL }, + { "stat", do_stat, 3, 2, awk_false, NULL }, + ... }; Each extension must have a routine named 'dl_load()' to load @@ -35320,573 +35388,574 @@ Index Tag Table: Node: Top1200 -Node: Foreword342726 -Node: Foreword447168 -Node: Preface48700 -Ref: Preface-Footnote-151559 -Ref: Preface-Footnote-251666 -Ref: Preface-Footnote-351900 -Node: History52042 -Node: Names54394 -Ref: Names-Footnote-155488 -Node: This Manual55635 -Ref: This Manual-Footnote-162120 -Node: Conventions62220 -Node: Manual History64574 -Ref: Manual History-Footnote-167569 -Ref: Manual History-Footnote-267610 -Node: How To Contribute67684 -Node: Acknowledgments68813 -Node: Getting Started73699 -Node: Running gawk76138 -Node: One-shot77328 -Node: Read Terminal78591 -Node: Long80584 -Node: Executable Scripts82097 -Ref: Executable Scripts-Footnote-184892 -Node: Comments84995 -Node: Quoting87479 -Node: DOS Quoting92996 -Node: Sample Data Files93671 -Node: Very Simple96266 -Node: Two Rules101168 -Node: More Complex103053 -Node: Statements/Lines105919 -Ref: Statements/Lines-Footnote-1110378 -Node: Other Features110643 -Node: When111579 -Ref: When-Footnote-1113333 -Node: Intro Summary113398 -Node: Invoking Gawk114282 -Node: Command Line115796 -Node: Options116594 -Ref: Options-Footnote-1132693 -Ref: Options-Footnote-2132923 -Node: Other Arguments132948 -Node: Naming Standard Input135895 -Node: Environment Variables136988 -Node: AWKPATH Variable137546 -Ref: AWKPATH Variable-Footnote-1140957 -Ref: AWKPATH Variable-Footnote-2140991 -Node: AWKLIBPATH Variable141252 -Node: Other Environment Variables142509 -Node: Exit Status146330 -Node: Include Files147007 -Node: Loading Shared Libraries150602 -Node: Obsolete152030 -Node: Undocumented152722 -Node: Invoking Summary153019 -Node: Regexp154679 -Node: Regexp Usage156133 -Node: Escape Sequences158170 -Node: Regexp Operators164402 -Ref: Regexp Operators-Footnote-1171818 -Ref: Regexp Operators-Footnote-2171965 -Node: Bracket Expressions172063 -Ref: table-char-classes174539 -Node: Leftmost Longest177676 -Node: Computed Regexps178979 -Node: GNU Regexp Operators182406 -Node: Case-sensitivity186085 -Ref: Case-sensitivity-Footnote-1188972 -Ref: Case-sensitivity-Footnote-2189207 -Node: Regexp Summary189315 -Node: Reading Files190781 -Node: Records192944 -Node: awk split records193677 -Node: gawk split records198608 -Ref: gawk split records-Footnote-1203148 -Node: Fields203185 -Node: Nonconstant Fields205926 -Ref: Nonconstant Fields-Footnote-1208162 -Node: Changing Fields208366 -Node: Field Separators214294 -Node: Default Field Splitting216992 -Node: Regexp Field Splitting218110 -Node: Single Character Fields221463 -Node: Command Line Field Separator222523 -Node: Full Line Fields225741 -Ref: Full Line Fields-Footnote-1227263 -Ref: Full Line Fields-Footnote-2227309 -Node: Field Splitting Summary227410 -Node: Constant Size229484 -Node: Splitting By Content234062 -Ref: Splitting By Content-Footnote-1238033 -Node: Multiple Line238196 -Ref: Multiple Line-Footnote-1244078 -Node: Getline244257 -Node: Plain Getline246724 -Node: Getline/Variable249363 -Node: Getline/File250512 -Node: Getline/Variable/File251898 -Ref: Getline/Variable/File-Footnote-1253501 -Node: Getline/Pipe253589 -Node: Getline/Variable/Pipe256294 -Node: Getline/Coprocess257427 -Node: Getline/Variable/Coprocess258692 -Node: Getline Notes259432 -Node: Getline Summary262227 -Ref: table-getline-variants262649 -Node: Read Timeout263397 -Ref: Read Timeout-Footnote-1267303 -Node: Retrying Input267361 -Node: Command-line directories268560 -Node: Input Summary269466 -Node: Input Exercises272638 -Node: Printing273366 -Node: Print275200 -Node: Print Examples276657 -Node: Output Separators279437 -Node: OFMT281454 -Node: Printf282810 -Node: Basic Printf283595 -Node: Control Letters285169 -Node: Format Modifiers289157 -Node: Printf Examples295172 -Node: Redirection297658 -Node: Special FD304499 -Ref: Special FD-Footnote-1307667 -Node: Special Files307741 -Node: Other Inherited Files308358 -Node: Special Network309359 -Node: Special Caveats310219 -Node: Close Files And Pipes311168 -Ref: table-close-pipe-return-values318075 -Ref: Close Files And Pipes-Footnote-1318858 -Ref: Close Files And Pipes-Footnote-2319006 -Node: Nonfatal319158 -Node: Output Summary321483 -Node: Output Exercises322705 -Node: Expressions323384 -Node: Values324572 -Node: Constants325250 -Node: Scalar Constants325941 -Ref: Scalar Constants-Footnote-1326805 -Node: Nondecimal-numbers327055 -Node: Regexp Constants330056 -Node: Using Constant Regexps330582 -Node: Standard Regexp Constants331204 -Node: Strong Regexp Constants334392 -Node: Variables337350 -Node: Using Variables338007 -Node: Assignment Options339917 -Node: Conversion341790 -Node: Strings And Numbers342314 -Ref: Strings And Numbers-Footnote-1345377 -Node: Locale influences conversions345486 -Ref: table-locale-affects348244 -Node: All Operators348862 -Node: Arithmetic Ops349491 -Node: Concatenation351997 -Ref: Concatenation-Footnote-1354844 -Node: Assignment Ops354951 -Ref: table-assign-ops359942 -Node: Increment Ops361255 -Node: Truth Values and Conditions364715 -Node: Truth Values365789 -Node: Typing and Comparison366837 -Node: Variable Typing367657 -Ref: Variable Typing-Footnote-1374120 -Ref: Variable Typing-Footnote-2374192 -Node: Comparison Operators374269 -Ref: table-relational-ops374688 -Node: POSIX String Comparison378183 -Ref: POSIX String Comparison-Footnote-1379878 -Ref: POSIX String Comparison-Footnote-2380017 -Node: Boolean Ops380101 -Ref: Boolean Ops-Footnote-1384583 -Node: Conditional Exp384675 -Node: Function Calls386411 -Node: Precedence390288 -Node: Locales393947 -Node: Expressions Summary395579 -Node: Patterns and Actions398152 -Node: Pattern Overview399272 -Node: Regexp Patterns400949 -Node: Expression Patterns401491 -Node: Ranges405272 -Node: BEGIN/END408380 -Node: Using BEGIN/END409141 -Ref: Using BEGIN/END-Footnote-1411877 -Node: I/O And BEGIN/END411983 -Node: BEGINFILE/ENDFILE414297 -Node: Empty417204 -Node: Using Shell Variables417521 -Node: Action Overview419795 -Node: Statements422120 -Node: If Statement423968 -Node: While Statement425463 -Node: Do Statement427491 -Node: For Statement428639 -Node: Switch Statement431797 -Node: Break Statement434183 -Node: Continue Statement436275 -Node: Next Statement438102 -Node: Nextfile Statement440485 -Node: Exit Statement443137 -Node: Built-in Variables445540 -Node: User-modified446673 -Node: Auto-set454259 -Ref: Auto-set-Footnote-1468912 -Ref: Auto-set-Footnote-2469118 -Node: ARGC and ARGV469174 -Node: Pattern Action Summary473387 -Node: Arrays475817 -Node: Array Basics477146 -Node: Array Intro477990 -Ref: figure-array-elements479965 -Ref: Array Intro-Footnote-1482669 -Node: Reference to Elements482797 -Node: Assigning Elements485261 -Node: Array Example485752 -Node: Scanning an Array487511 -Node: Controlling Scanning490533 -Ref: Controlling Scanning-Footnote-1495932 -Node: Numeric Array Subscripts496248 -Node: Uninitialized Subscripts498432 -Node: Delete500051 -Ref: Delete-Footnote-1502803 -Node: Multidimensional502860 -Node: Multiscanning505955 -Node: Arrays of Arrays507546 -Node: Arrays Summary512313 -Node: Functions514406 -Node: Built-in515444 -Node: Calling Built-in516525 -Node: Numeric Functions518521 -Ref: Numeric Functions-Footnote-1523354 -Ref: Numeric Functions-Footnote-2523711 -Ref: Numeric Functions-Footnote-3523759 -Node: String Functions524031 -Ref: String Functions-Footnote-1547535 -Ref: String Functions-Footnote-2547663 -Ref: String Functions-Footnote-3547911 -Node: Gory Details547998 -Ref: table-sub-escapes549789 -Ref: table-sub-proposed551308 -Ref: table-posix-sub552671 -Ref: table-gensub-escapes554212 -Ref: Gory Details-Footnote-1555035 -Node: I/O Functions555189 -Ref: table-system-return-values561771 -Ref: I/O Functions-Footnote-1563751 -Ref: I/O Functions-Footnote-2563899 -Node: Time Functions564019 -Ref: Time Functions-Footnote-1574541 -Ref: Time Functions-Footnote-2574609 -Ref: Time Functions-Footnote-3574767 -Ref: Time Functions-Footnote-4574878 -Ref: Time Functions-Footnote-5574990 -Ref: Time Functions-Footnote-6575217 -Node: Bitwise Functions575483 -Ref: table-bitwise-ops576077 -Ref: Bitwise Functions-Footnote-1582103 -Ref: Bitwise Functions-Footnote-2582276 -Node: Type Functions582467 -Node: I18N Functions585143 -Node: User-defined586794 -Node: Definition Syntax587599 -Ref: Definition Syntax-Footnote-1593286 -Node: Function Example593357 -Ref: Function Example-Footnote-1596279 -Node: Function Caveats596301 -Node: Calling A Function596819 -Node: Variable Scope597777 -Node: Pass By Value/Reference600771 -Node: Return Statement604270 -Node: Dynamic Typing607249 -Node: Indirect Calls608179 -Ref: Indirect Calls-Footnote-1618430 -Node: Functions Summary618558 -Node: Library Functions621263 -Ref: Library Functions-Footnote-1624870 -Ref: Library Functions-Footnote-2625013 -Node: Library Names625184 -Ref: Library Names-Footnote-1628644 -Ref: Library Names-Footnote-2628867 -Node: General Functions628953 -Node: Strtonum Function630056 -Node: Assert Function633078 -Node: Round Function636404 -Node: Cliff Random Function637945 -Node: Ordinal Functions638961 -Ref: Ordinal Functions-Footnote-1642024 -Ref: Ordinal Functions-Footnote-2642276 -Node: Join Function642486 -Ref: Join Function-Footnote-1644256 -Node: Getlocaltime Function644456 -Node: Readfile Function648198 -Node: Shell Quoting650170 -Node: Data File Management651571 -Node: Filetrans Function652203 -Node: Rewind Function656299 -Node: File Checking658205 -Ref: File Checking-Footnote-1659539 -Node: Empty Files659740 -Node: Ignoring Assigns661719 -Node: Getopt Function663269 -Ref: Getopt Function-Footnote-1674738 -Node: Passwd Functions674938 -Ref: Passwd Functions-Footnote-1683777 -Node: Group Functions683865 -Ref: Group Functions-Footnote-1691763 -Node: Walking Arrays691970 -Node: Library Functions Summary694978 -Node: Library Exercises696384 -Node: Sample Programs696849 -Node: Running Examples697619 -Node: Clones698347 -Node: Cut Program699571 -Node: Egrep Program709500 -Ref: Egrep Program-Footnote-1717012 -Node: Id Program717122 -Node: Split Program720802 -Ref: Split Program-Footnote-1724261 -Node: Tee Program724390 -Node: Uniq Program727180 -Node: Wc Program734606 -Ref: Wc Program-Footnote-1738861 -Node: Miscellaneous Programs738955 -Node: Dupword Program740168 -Node: Alarm Program742198 -Node: Translate Program747053 -Ref: Translate Program-Footnote-1751618 -Node: Labels Program751888 -Ref: Labels Program-Footnote-1755239 -Node: Word Sorting755323 -Node: History Sorting759395 -Node: Extract Program761230 -Node: Simple Sed768759 -Node: Igawk Program771833 -Ref: Igawk Program-Footnote-1786164 -Ref: Igawk Program-Footnote-2786366 -Ref: Igawk Program-Footnote-3786488 -Node: Anagram Program786603 -Node: Signature Program789665 -Node: Programs Summary790912 -Node: Programs Exercises792126 -Ref: Programs Exercises-Footnote-1796255 -Node: Advanced Features796346 -Node: Nondecimal Data798336 -Node: Array Sorting799927 -Node: Controlling Array Traversal800627 -Ref: Controlling Array Traversal-Footnote-1808994 -Node: Array Sorting Functions809112 -Ref: Array Sorting Functions-Footnote-1814203 -Node: Two-way I/O814399 -Ref: Two-way I/O-Footnote-1820949 -Ref: Two-way I/O-Footnote-2821136 -Node: TCP/IP Networking821218 -Node: Profiling824336 -Ref: Profiling-Footnote-1832829 -Node: Advanced Features Summary833152 -Node: Internationalization834996 -Node: I18N and L10N836476 -Node: Explaining gettext837163 -Ref: Explaining gettext-Footnote-1843055 -Ref: Explaining gettext-Footnote-2843240 -Node: Programmer i18n843405 -Ref: Programmer i18n-Footnote-1848354 -Node: Translator i18n848403 -Node: String Extraction849197 -Ref: String Extraction-Footnote-1850329 -Node: Printf Ordering850415 -Ref: Printf Ordering-Footnote-1853201 -Node: I18N Portability853265 -Ref: I18N Portability-Footnote-1855721 -Node: I18N Example855784 -Ref: I18N Example-Footnote-1858590 -Node: Gawk I18N858663 -Node: I18N Summary859308 -Node: Debugger860649 -Node: Debugging861671 -Node: Debugging Concepts862112 -Node: Debugging Terms863921 -Node: Awk Debugging866496 -Node: Sample Debugging Session867402 -Node: Debugger Invocation867936 -Node: Finding The Bug869322 -Node: List of Debugger Commands875800 -Node: Breakpoint Control877133 -Node: Debugger Execution Control880827 -Node: Viewing And Changing Data884189 -Node: Execution Stack887563 -Node: Debugger Info889200 -Node: Miscellaneous Debugger Commands893271 -Node: Readline Support898359 -Node: Limitations899255 -Node: Debugging Summary901364 -Node: Arbitrary Precision Arithmetic902643 -Node: Computer Arithmetic904059 -Ref: table-numeric-ranges907650 -Ref: Computer Arithmetic-Footnote-1908372 -Node: Math Definitions908429 -Ref: table-ieee-formats911743 -Ref: Math Definitions-Footnote-1912346 -Node: MPFR features912451 -Node: FP Math Caution914168 -Ref: FP Math Caution-Footnote-1915240 -Node: Inexactness of computations915609 -Node: Inexact representation916569 -Node: Comparing FP Values917929 -Node: Errors accumulate919011 -Node: Getting Accuracy920444 -Node: Try To Round923154 -Node: Setting precision924053 -Ref: table-predefined-precision-strings924750 -Node: Setting the rounding mode926580 -Ref: table-gawk-rounding-modes926954 -Ref: Setting the rounding mode-Footnote-1930362 -Node: Arbitrary Precision Integers930541 -Ref: Arbitrary Precision Integers-Footnote-1935458 -Node: POSIX Floating Point Problems935607 -Ref: POSIX Floating Point Problems-Footnote-1939489 -Node: Floating point summary939527 -Node: Dynamic Extensions941717 -Node: Extension Intro943270 -Node: Plugin License944536 -Node: Extension Mechanism Outline945333 -Ref: figure-load-extension945772 -Ref: figure-register-new-function947337 -Ref: figure-call-new-function948429 -Node: Extension API Description950491 -Node: Extension API Functions Introduction952064 -Node: General Data Types957375 -Ref: General Data Types-Footnote-1963330 -Node: Memory Allocation Functions963629 -Ref: Memory Allocation Functions-Footnote-1966474 -Node: Constructor Functions966573 -Node: Registration Functions968318 -Node: Extension Functions969003 -Node: Exit Callback Functions971626 -Node: Extension Version String972876 -Node: Input Parsers973539 -Node: Output Wrappers983421 -Node: Two-way processors987933 -Node: Printing Messages990198 -Ref: Printing Messages-Footnote-1991369 -Node: Updating ERRNO991522 -Node: Requesting Values992261 -Ref: table-value-types-returned992998 -Node: Accessing Parameters993881 -Node: Symbol Table Access995116 -Node: Symbol table by name995628 -Node: Symbol table by cookie997649 -Ref: Symbol table by cookie-Footnote-11001801 -Node: Cached values1001865 -Ref: Cached values-Footnote-11005372 -Node: Array Manipulation1005463 -Ref: Array Manipulation-Footnote-11006554 -Node: Array Data Types1006591 -Ref: Array Data Types-Footnote-11009249 -Node: Array Functions1009341 -Node: Flattening Arrays1013199 -Node: Creating Arrays1020107 -Node: Redirection API1024876 -Node: Extension API Variables1027707 -Node: Extension Versioning1028340 -Ref: gawk-api-version1028777 -Node: Extension API Informational Variables1030533 -Node: Extension API Boilerplate1031597 -Node: Finding Extensions1035411 -Node: Extension Example1035970 -Node: Internal File Description1036768 -Node: Internal File Ops1040848 -Ref: Internal File Ops-Footnote-11052610 -Node: Using Internal File Ops1052750 -Ref: Using Internal File Ops-Footnote-11055133 -Node: Extension Samples1055407 -Node: Extension Sample File Functions1056936 -Node: Extension Sample Fnmatch1064585 -Node: Extension Sample Fork1066072 -Node: Extension Sample Inplace1067290 -Node: Extension Sample Ord1070500 -Node: Extension Sample Readdir1071336 -Ref: table-readdir-file-types1072225 -Node: Extension Sample Revout1073030 -Node: Extension Sample Rev2way1073619 -Node: Extension Sample Read write array1074359 -Node: Extension Sample Readfile1076301 -Node: Extension Sample Time1077396 -Node: Extension Sample API Tests1078744 -Node: gawkextlib1079236 -Node: Extension summary1081683 -Node: Extension Exercises1085385 -Node: Language History1086883 -Node: V7/SVR3.11088539 -Node: SVR41090691 -Node: POSIX1092125 -Node: BTL1093504 -Node: POSIX/GNU1094233 -Node: Feature History1100095 -Node: Common Extensions1114465 -Node: Ranges and Locales1115748 -Ref: Ranges and Locales-Footnote-11120364 -Ref: Ranges and Locales-Footnote-21120391 -Ref: Ranges and Locales-Footnote-31120626 -Node: Contributors1120847 -Node: History summary1126407 -Node: Installation1127787 -Node: Gawk Distribution1128731 -Node: Getting1129215 -Node: Extracting1130176 -Node: Distribution contents1131814 -Node: Unix Installation1137899 -Node: Quick Installation1138581 -Node: Shell Startup Files1140995 -Node: Additional Configuration Options1142073 -Node: Configuration Philosophy1143878 -Node: Non-Unix Installation1146247 -Node: PC Installation1146707 -Node: PC Binary Installation1147545 -Node: PC Compiling1147980 -Node: PC Using1149097 -Node: Cygwin1152142 -Node: MSYS1152912 -Node: VMS Installation1153413 -Node: VMS Compilation1154204 -Ref: VMS Compilation-Footnote-11155433 -Node: VMS Dynamic Extensions1155491 -Node: VMS Installation Details1157176 -Node: VMS Running1159429 -Node: VMS GNV1163708 -Node: VMS Old Gawk1164443 -Node: Bugs1164914 -Node: Bug address1165577 -Node: Usenet1167974 -Node: Maintainers1168749 -Node: Other Versions1170125 -Node: Installation summary1176709 -Node: Notes1177744 -Node: Compatibility Mode1178609 -Node: Additions1179391 -Node: Accessing The Source1180316 -Node: Adding Code1181751 -Node: New Ports1187970 -Node: Derived Files1192458 -Ref: Derived Files-Footnote-11197943 -Ref: Derived Files-Footnote-21197978 -Ref: Derived Files-Footnote-31198576 -Node: Future Extensions1198690 -Node: Implementation Limitations1199348 -Node: Extension Design1200531 -Node: Old Extension Problems1201685 -Ref: Old Extension Problems-Footnote-11203203 -Node: Extension New Mechanism Goals1203260 -Ref: Extension New Mechanism Goals-Footnote-11206624 -Node: Extension Other Design Decisions1206813 -Node: Extension Future Growth1208926 -Node: Old Extension Mechanism1209762 -Node: Notes summary1211525 -Node: Basic Concepts1212707 -Node: Basic High Level1213388 -Ref: figure-general-flow1213670 -Ref: figure-process-flow1214355 -Ref: Basic High Level-Footnote-11217656 -Node: Basic Data Typing1217841 -Node: Glossary1221169 -Node: Copying1253116 -Node: GNU Free Documentation License1290655 -Node: Index1315773 +Node: Foreword342794 +Node: Foreword447236 +Node: Preface48768 +Ref: Preface-Footnote-151627 +Ref: Preface-Footnote-251734 +Ref: Preface-Footnote-351968 +Node: History52110 +Node: Names54462 +Ref: Names-Footnote-155556 +Node: This Manual55703 +Ref: This Manual-Footnote-162188 +Node: Conventions62288 +Node: Manual History64642 +Ref: Manual History-Footnote-167637 +Ref: Manual History-Footnote-267678 +Node: How To Contribute67752 +Node: Acknowledgments68881 +Node: Getting Started73767 +Node: Running gawk76206 +Node: One-shot77396 +Node: Read Terminal78659 +Node: Long80652 +Node: Executable Scripts82165 +Ref: Executable Scripts-Footnote-184960 +Node: Comments85063 +Node: Quoting87547 +Node: DOS Quoting93064 +Node: Sample Data Files93739 +Node: Very Simple96334 +Node: Two Rules101236 +Node: More Complex103121 +Node: Statements/Lines105987 +Ref: Statements/Lines-Footnote-1110446 +Node: Other Features110711 +Node: When111647 +Ref: When-Footnote-1113401 +Node: Intro Summary113466 +Node: Invoking Gawk114350 +Node: Command Line115864 +Node: Options116662 +Ref: Options-Footnote-1132761 +Ref: Options-Footnote-2132991 +Node: Other Arguments133016 +Node: Naming Standard Input135963 +Node: Environment Variables137056 +Node: AWKPATH Variable137614 +Ref: AWKPATH Variable-Footnote-1141025 +Ref: AWKPATH Variable-Footnote-2141059 +Node: AWKLIBPATH Variable141320 +Node: Other Environment Variables142577 +Node: Exit Status146398 +Node: Include Files147075 +Node: Loading Shared Libraries150670 +Node: Obsolete152098 +Node: Undocumented152790 +Node: Invoking Summary153087 +Node: Regexp154747 +Node: Regexp Usage156201 +Node: Escape Sequences158238 +Node: Regexp Operators164470 +Ref: Regexp Operators-Footnote-1171886 +Ref: Regexp Operators-Footnote-2172033 +Node: Bracket Expressions172131 +Ref: table-char-classes174607 +Node: Leftmost Longest177744 +Node: Computed Regexps179047 +Node: GNU Regexp Operators182474 +Node: Case-sensitivity186153 +Ref: Case-sensitivity-Footnote-1189040 +Ref: Case-sensitivity-Footnote-2189275 +Node: Regexp Summary189383 +Node: Reading Files190849 +Node: Records193012 +Node: awk split records193745 +Node: gawk split records198676 +Ref: gawk split records-Footnote-1203216 +Node: Fields203253 +Node: Nonconstant Fields205994 +Ref: Nonconstant Fields-Footnote-1208230 +Node: Changing Fields208434 +Node: Field Separators214362 +Node: Default Field Splitting217060 +Node: Regexp Field Splitting218178 +Node: Single Character Fields221531 +Node: Command Line Field Separator222591 +Node: Full Line Fields225809 +Ref: Full Line Fields-Footnote-1227331 +Ref: Full Line Fields-Footnote-2227377 +Node: Field Splitting Summary227478 +Node: Constant Size229552 +Node: Splitting By Content234130 +Ref: Splitting By Content-Footnote-1238101 +Node: Multiple Line238264 +Ref: Multiple Line-Footnote-1244146 +Node: Getline244325 +Node: Plain Getline246792 +Node: Getline/Variable249431 +Node: Getline/File250580 +Node: Getline/Variable/File251966 +Ref: Getline/Variable/File-Footnote-1253569 +Node: Getline/Pipe253657 +Node: Getline/Variable/Pipe256362 +Node: Getline/Coprocess257495 +Node: Getline/Variable/Coprocess258760 +Node: Getline Notes259500 +Node: Getline Summary262295 +Ref: table-getline-variants262717 +Node: Read Timeout263465 +Ref: Read Timeout-Footnote-1267371 +Node: Retrying Input267429 +Node: Command-line directories268628 +Node: Input Summary269534 +Node: Input Exercises272706 +Node: Printing273434 +Node: Print275268 +Node: Print Examples276725 +Node: Output Separators279505 +Node: OFMT281522 +Node: Printf282878 +Node: Basic Printf283663 +Node: Control Letters285237 +Node: Format Modifiers289225 +Node: Printf Examples295240 +Node: Redirection297726 +Node: Special FD304567 +Ref: Special FD-Footnote-1307735 +Node: Special Files307809 +Node: Other Inherited Files308426 +Node: Special Network309427 +Node: Special Caveats310287 +Node: Close Files And Pipes311236 +Ref: table-close-pipe-return-values318143 +Ref: Close Files And Pipes-Footnote-1318926 +Ref: Close Files And Pipes-Footnote-2319074 +Node: Nonfatal319226 +Node: Output Summary321551 +Node: Output Exercises322773 +Node: Expressions323452 +Node: Values324640 +Node: Constants325318 +Node: Scalar Constants326009 +Ref: Scalar Constants-Footnote-1326873 +Node: Nondecimal-numbers327123 +Node: Regexp Constants330124 +Node: Using Constant Regexps330650 +Node: Standard Regexp Constants331272 +Node: Strong Regexp Constants334460 +Node: Variables337418 +Node: Using Variables338075 +Node: Assignment Options339985 +Node: Conversion341858 +Node: Strings And Numbers342382 +Ref: Strings And Numbers-Footnote-1345445 +Node: Locale influences conversions345554 +Ref: table-locale-affects348312 +Node: All Operators348930 +Node: Arithmetic Ops349559 +Node: Concatenation352065 +Ref: Concatenation-Footnote-1354912 +Node: Assignment Ops355019 +Ref: table-assign-ops360010 +Node: Increment Ops361323 +Node: Truth Values and Conditions364783 +Node: Truth Values365857 +Node: Typing and Comparison366905 +Node: Variable Typing367725 +Ref: Variable Typing-Footnote-1374188 +Ref: Variable Typing-Footnote-2374260 +Node: Comparison Operators374337 +Ref: table-relational-ops374756 +Node: POSIX String Comparison378251 +Ref: POSIX String Comparison-Footnote-1379946 +Ref: POSIX String Comparison-Footnote-2380085 +Node: Boolean Ops380169 +Ref: Boolean Ops-Footnote-1384651 +Node: Conditional Exp384743 +Node: Function Calls386479 +Node: Precedence390356 +Node: Locales394015 +Node: Expressions Summary395647 +Node: Patterns and Actions398220 +Node: Pattern Overview399340 +Node: Regexp Patterns401017 +Node: Expression Patterns401559 +Node: Ranges405340 +Node: BEGIN/END408448 +Node: Using BEGIN/END409209 +Ref: Using BEGIN/END-Footnote-1411945 +Node: I/O And BEGIN/END412051 +Node: BEGINFILE/ENDFILE414365 +Node: Empty417272 +Node: Using Shell Variables417589 +Node: Action Overview419863 +Node: Statements422188 +Node: If Statement424036 +Node: While Statement425531 +Node: Do Statement427559 +Node: For Statement428707 +Node: Switch Statement431865 +Node: Break Statement434251 +Node: Continue Statement436343 +Node: Next Statement438170 +Node: Nextfile Statement440553 +Node: Exit Statement443205 +Node: Built-in Variables445608 +Node: User-modified446741 +Node: Auto-set454327 +Ref: Auto-set-Footnote-1468980 +Ref: Auto-set-Footnote-2469186 +Node: ARGC and ARGV469242 +Node: Pattern Action Summary473455 +Node: Arrays475885 +Node: Array Basics477214 +Node: Array Intro478058 +Ref: figure-array-elements480033 +Ref: Array Intro-Footnote-1482737 +Node: Reference to Elements482865 +Node: Assigning Elements485329 +Node: Array Example485820 +Node: Scanning an Array487579 +Node: Controlling Scanning490601 +Ref: Controlling Scanning-Footnote-1496000 +Node: Numeric Array Subscripts496316 +Node: Uninitialized Subscripts498500 +Node: Delete500119 +Ref: Delete-Footnote-1502871 +Node: Multidimensional502928 +Node: Multiscanning506023 +Node: Arrays of Arrays507614 +Node: Arrays Summary512381 +Node: Functions514474 +Node: Built-in515512 +Node: Calling Built-in516593 +Node: Numeric Functions518589 +Ref: Numeric Functions-Footnote-1523422 +Ref: Numeric Functions-Footnote-2523779 +Ref: Numeric Functions-Footnote-3523827 +Node: String Functions524099 +Ref: String Functions-Footnote-1547603 +Ref: String Functions-Footnote-2547731 +Ref: String Functions-Footnote-3547979 +Node: Gory Details548066 +Ref: table-sub-escapes549857 +Ref: table-sub-proposed551376 +Ref: table-posix-sub552739 +Ref: table-gensub-escapes554280 +Ref: Gory Details-Footnote-1555103 +Node: I/O Functions555257 +Ref: table-system-return-values561839 +Ref: I/O Functions-Footnote-1563819 +Ref: I/O Functions-Footnote-2563967 +Node: Time Functions564087 +Ref: Time Functions-Footnote-1574609 +Ref: Time Functions-Footnote-2574677 +Ref: Time Functions-Footnote-3574835 +Ref: Time Functions-Footnote-4574946 +Ref: Time Functions-Footnote-5575058 +Ref: Time Functions-Footnote-6575285 +Node: Bitwise Functions575551 +Ref: table-bitwise-ops576145 +Ref: Bitwise Functions-Footnote-1582171 +Ref: Bitwise Functions-Footnote-2582344 +Node: Type Functions582535 +Node: I18N Functions585211 +Node: User-defined586862 +Node: Definition Syntax587667 +Ref: Definition Syntax-Footnote-1593354 +Node: Function Example593425 +Ref: Function Example-Footnote-1596347 +Node: Function Caveats596369 +Node: Calling A Function596887 +Node: Variable Scope597845 +Node: Pass By Value/Reference600839 +Node: Return Statement604338 +Node: Dynamic Typing607317 +Node: Indirect Calls608247 +Ref: Indirect Calls-Footnote-1618498 +Node: Functions Summary618626 +Node: Library Functions621331 +Ref: Library Functions-Footnote-1624938 +Ref: Library Functions-Footnote-2625081 +Node: Library Names625252 +Ref: Library Names-Footnote-1628712 +Ref: Library Names-Footnote-2628935 +Node: General Functions629021 +Node: Strtonum Function630124 +Node: Assert Function633146 +Node: Round Function636472 +Node: Cliff Random Function638013 +Node: Ordinal Functions639029 +Ref: Ordinal Functions-Footnote-1642092 +Ref: Ordinal Functions-Footnote-2642344 +Node: Join Function642554 +Ref: Join Function-Footnote-1644324 +Node: Getlocaltime Function644524 +Node: Readfile Function648266 +Node: Shell Quoting650238 +Node: Data File Management651639 +Node: Filetrans Function652271 +Node: Rewind Function656367 +Node: File Checking658273 +Ref: File Checking-Footnote-1659607 +Node: Empty Files659808 +Node: Ignoring Assigns661787 +Node: Getopt Function663337 +Ref: Getopt Function-Footnote-1674806 +Node: Passwd Functions675006 +Ref: Passwd Functions-Footnote-1683845 +Node: Group Functions683933 +Ref: Group Functions-Footnote-1691831 +Node: Walking Arrays692038 +Node: Library Functions Summary695046 +Node: Library Exercises696452 +Node: Sample Programs696917 +Node: Running Examples697687 +Node: Clones698415 +Node: Cut Program699639 +Node: Egrep Program709568 +Ref: Egrep Program-Footnote-1717080 +Node: Id Program717190 +Node: Split Program720870 +Ref: Split Program-Footnote-1724329 +Node: Tee Program724458 +Node: Uniq Program727248 +Node: Wc Program734674 +Ref: Wc Program-Footnote-1738929 +Node: Miscellaneous Programs739023 +Node: Dupword Program740236 +Node: Alarm Program742266 +Node: Translate Program747121 +Ref: Translate Program-Footnote-1751686 +Node: Labels Program751956 +Ref: Labels Program-Footnote-1755307 +Node: Word Sorting755391 +Node: History Sorting759463 +Node: Extract Program761298 +Node: Simple Sed768827 +Node: Igawk Program771901 +Ref: Igawk Program-Footnote-1786232 +Ref: Igawk Program-Footnote-2786434 +Ref: Igawk Program-Footnote-3786556 +Node: Anagram Program786671 +Node: Signature Program789733 +Node: Programs Summary790980 +Node: Programs Exercises792194 +Ref: Programs Exercises-Footnote-1796323 +Node: Advanced Features796414 +Node: Nondecimal Data798404 +Node: Array Sorting799995 +Node: Controlling Array Traversal800695 +Ref: Controlling Array Traversal-Footnote-1809062 +Node: Array Sorting Functions809180 +Ref: Array Sorting Functions-Footnote-1814271 +Node: Two-way I/O814467 +Ref: Two-way I/O-Footnote-1821017 +Ref: Two-way I/O-Footnote-2821204 +Node: TCP/IP Networking821286 +Node: Profiling824404 +Ref: Profiling-Footnote-1832897 +Node: Advanced Features Summary833220 +Node: Internationalization835064 +Node: I18N and L10N836544 +Node: Explaining gettext837231 +Ref: Explaining gettext-Footnote-1843123 +Ref: Explaining gettext-Footnote-2843308 +Node: Programmer i18n843473 +Ref: Programmer i18n-Footnote-1848422 +Node: Translator i18n848471 +Node: String Extraction849265 +Ref: String Extraction-Footnote-1850397 +Node: Printf Ordering850483 +Ref: Printf Ordering-Footnote-1853269 +Node: I18N Portability853333 +Ref: I18N Portability-Footnote-1855789 +Node: I18N Example855852 +Ref: I18N Example-Footnote-1858658 +Node: Gawk I18N858731 +Node: I18N Summary859376 +Node: Debugger860717 +Node: Debugging861739 +Node: Debugging Concepts862180 +Node: Debugging Terms863989 +Node: Awk Debugging866564 +Node: Sample Debugging Session867470 +Node: Debugger Invocation868004 +Node: Finding The Bug869390 +Node: List of Debugger Commands875868 +Node: Breakpoint Control877201 +Node: Debugger Execution Control880895 +Node: Viewing And Changing Data884257 +Node: Execution Stack887631 +Node: Debugger Info889268 +Node: Miscellaneous Debugger Commands893339 +Node: Readline Support898427 +Node: Limitations899323 +Node: Debugging Summary901432 +Node: Arbitrary Precision Arithmetic902711 +Node: Computer Arithmetic904127 +Ref: table-numeric-ranges907718 +Ref: Computer Arithmetic-Footnote-1908440 +Node: Math Definitions908497 +Ref: table-ieee-formats911811 +Ref: Math Definitions-Footnote-1912414 +Node: MPFR features912519 +Node: FP Math Caution914236 +Ref: FP Math Caution-Footnote-1915308 +Node: Inexactness of computations915677 +Node: Inexact representation916637 +Node: Comparing FP Values917997 +Node: Errors accumulate919079 +Node: Getting Accuracy920512 +Node: Try To Round923222 +Node: Setting precision924121 +Ref: table-predefined-precision-strings924818 +Node: Setting the rounding mode926648 +Ref: table-gawk-rounding-modes927022 +Ref: Setting the rounding mode-Footnote-1930430 +Node: Arbitrary Precision Integers930609 +Ref: Arbitrary Precision Integers-Footnote-1935526 +Node: POSIX Floating Point Problems935675 +Ref: POSIX Floating Point Problems-Footnote-1939557 +Node: Floating point summary939595 +Node: Dynamic Extensions941785 +Node: Extension Intro943338 +Node: Plugin License944604 +Node: Extension Mechanism Outline945401 +Ref: figure-load-extension945840 +Ref: figure-register-new-function947405 +Ref: figure-call-new-function948497 +Node: Extension API Description950559 +Node: Extension API Functions Introduction952201 +Node: General Data Types957512 +Ref: General Data Types-Footnote-1963823 +Node: Memory Allocation Functions964122 +Ref: Memory Allocation Functions-Footnote-1966967 +Node: Constructor Functions967066 +Node: Registration Functions969028 +Node: Extension Functions969713 +Node: Exit Callback Functions974911 +Node: Extension Version String976161 +Node: Input Parsers976824 +Node: Output Wrappers986706 +Node: Two-way processors991218 +Node: Printing Messages993483 +Ref: Printing Messages-Footnote-1994654 +Node: Updating ERRNO994807 +Node: Requesting Values995546 +Ref: table-value-types-returned996283 +Node: Accessing Parameters997166 +Node: Symbol Table Access998401 +Node: Symbol table by name998913 +Node: Symbol table by cookie1000702 +Ref: Symbol table by cookie-Footnote-11004873 +Node: Cached values1004937 +Ref: Cached values-Footnote-11008458 +Node: Array Manipulation1008549 +Ref: Array Manipulation-Footnote-11009640 +Node: Array Data Types1009677 +Ref: Array Data Types-Footnote-11012335 +Node: Array Functions1012427 +Node: Flattening Arrays1016285 +Node: Creating Arrays1023193 +Node: Redirection API1027962 +Node: Extension API Variables1030793 +Node: Extension Versioning1031426 +Ref: gawk-api-version1031863 +Node: Extension API Informational Variables1033591 +Node: Extension API Boilerplate1034655 +Node: Changes from API V11038517 +Node: Finding Extensions1039177 +Node: Extension Example1039736 +Node: Internal File Description1040534 +Node: Internal File Ops1044614 +Ref: Internal File Ops-Footnote-11056014 +Node: Using Internal File Ops1056154 +Ref: Using Internal File Ops-Footnote-11058537 +Node: Extension Samples1058811 +Node: Extension Sample File Functions1060340 +Node: Extension Sample Fnmatch1067989 +Node: Extension Sample Fork1069476 +Node: Extension Sample Inplace1070694 +Node: Extension Sample Ord1073904 +Node: Extension Sample Readdir1074740 +Ref: table-readdir-file-types1075629 +Node: Extension Sample Revout1076434 +Node: Extension Sample Rev2way1077023 +Node: Extension Sample Read write array1077763 +Node: Extension Sample Readfile1079705 +Node: Extension Sample Time1080800 +Node: Extension Sample API Tests1082148 +Node: gawkextlib1082640 +Node: Extension summary1085087 +Node: Extension Exercises1088789 +Node: Language History1090287 +Node: V7/SVR3.11091943 +Node: SVR41094095 +Node: POSIX1095529 +Node: BTL1096908 +Node: POSIX/GNU1097637 +Node: Feature History1103499 +Node: Common Extensions1117869 +Node: Ranges and Locales1119152 +Ref: Ranges and Locales-Footnote-11123768 +Ref: Ranges and Locales-Footnote-21123795 +Ref: Ranges and Locales-Footnote-31124030 +Node: Contributors1124251 +Node: History summary1129811 +Node: Installation1131191 +Node: Gawk Distribution1132135 +Node: Getting1132619 +Node: Extracting1133580 +Node: Distribution contents1135218 +Node: Unix Installation1141303 +Node: Quick Installation1141985 +Node: Shell Startup Files1144399 +Node: Additional Configuration Options1145477 +Node: Configuration Philosophy1147282 +Node: Non-Unix Installation1149651 +Node: PC Installation1150111 +Node: PC Binary Installation1150949 +Node: PC Compiling1151384 +Node: PC Using1152501 +Node: Cygwin1155546 +Node: MSYS1156316 +Node: VMS Installation1156817 +Node: VMS Compilation1157608 +Ref: VMS Compilation-Footnote-11158837 +Node: VMS Dynamic Extensions1158895 +Node: VMS Installation Details1160580 +Node: VMS Running1162833 +Node: VMS GNV1167112 +Node: VMS Old Gawk1167847 +Node: Bugs1168318 +Node: Bug address1168981 +Node: Usenet1171378 +Node: Maintainers1172153 +Node: Other Versions1173529 +Node: Installation summary1180113 +Node: Notes1181148 +Node: Compatibility Mode1182013 +Node: Additions1182795 +Node: Accessing The Source1183720 +Node: Adding Code1185155 +Node: New Ports1191374 +Node: Derived Files1195862 +Ref: Derived Files-Footnote-11201347 +Ref: Derived Files-Footnote-21201382 +Ref: Derived Files-Footnote-31201980 +Node: Future Extensions1202094 +Node: Implementation Limitations1202752 +Node: Extension Design1203935 +Node: Old Extension Problems1205089 +Ref: Old Extension Problems-Footnote-11206607 +Node: Extension New Mechanism Goals1206664 +Ref: Extension New Mechanism Goals-Footnote-11210028 +Node: Extension Other Design Decisions1210217 +Node: Extension Future Growth1212330 +Node: Old Extension Mechanism1213166 +Node: Notes summary1214929 +Node: Basic Concepts1216111 +Node: Basic High Level1216792 +Ref: figure-general-flow1217074 +Ref: figure-process-flow1217759 +Ref: Basic High Level-Footnote-11221060 +Node: Basic Data Typing1221245 +Node: Glossary1224573 +Node: Copying1256520 +Node: GNU Free Documentation License1294059 +Node: Index1319177 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 5f3d6efa..35db3479 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -933,6 +933,7 @@ particular records in a file and perform operations upon them. * Extension API Informational Variables:: Variables providing information about @command{gawk}'s invocation. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. * Finding Extensions:: How @command{gawk} finds compiled extensions. * Extension Example:: Example C code for an extension. @@ -32323,6 +32324,7 @@ This (rather large) @value{SECTION} describes the API in detail. redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. @end menu @node Extension API Functions Introduction @@ -32557,7 +32559,8 @@ multibyte encoding. @itemx @ @ @ @ AWK_STRING, @itemx @ @ @ @ AWK_ARRAY, @itemx @ @ @ @ AWK_SCALAR,@ @ @ @ @ @ @ @ @ /* opaque access to a variable */ -@itemx @ @ @ @ AWK_VALUE_COOKIE@ @ @ @ /* for updating a previously created value */ +@itemx @ @ @ @ AWK_VALUE_COOKIE,@ @ @ /* for updating a previously created value */ +@itemx @ @ @ @ AWK_REGEX @itemx @} awk_valtype_t; This @code{enum} indicates the type of a value. It is used in the following @code{struct}. @@ -32577,6 +32580,7 @@ The @code{val_type} member indicates what kind of value the @code{union} holds, and each member is of the appropriate type. @item #define str_value@ @ @ @ @ @ u.s +@itemx #define regex_value@ @ @ @ str_value @itemx #define num_value@ @ @ @ @ @ u.d @itemx #define array_cookie@ @ @ u.a @itemx #define scalar_cookie@ @ u.scl @@ -32597,7 +32601,7 @@ and in more detail in @ref{Cached values}. @end table -Scalar values in @command{awk} are either numbers or strings. The +Scalar values in @command{awk} are numbers, strings, or typed regexps. The @code{awk_value_t} struct represents values. The @code{val_type} member indicates what is in the @code{union}. @@ -32606,6 +32610,12 @@ require more work. Because @command{gawk} allows embedded @sc{nul} bytes in string values, a string must be represented as a pair containing a data pointer and length. This is the @code{awk_string_t} type. +Typed regexp values (@pxref{Strong Regexp Constants}) are not of +much use to extension functions. Extension functions can tell that +they've received them, and create them for scalar values. Otherwise, +they can examine the text of the regexp through @code{regex_value.str} +and @code{regex_value.len}. + Identifiers (i.e., the names of global variables) can be associated with either scalar values or with arrays. In addition, @command{gawk} provides true arrays of arrays, where any given array element can @@ -32772,6 +32782,11 @@ It returns @code{result}. @itemx make_number(double num, awk_value_t *result); This function simply creates a numeric value in the @code{awk_value_t} variable pointed to by @code{result}. + +@item static inline awk_value_t * +@itemx make_regex(const char *string, size_t length, awk_value_t *result); +This function creates a strongly typed regexp value. +@code{string} is the regular expression of length @code{len}. @end table @node Registration Functions @@ -32799,8 +32814,13 @@ Extension functions are described by the following record: @example typedef struct awk_ext_func @{ @ @ @ @ const char *name; -@ @ @ @ awk_value_t *(*function)(int num_actual_args, awk_value_t *result); -@ @ @ @ size_t max_expected_args; +@ @ @ @ awk_value_t *(*const function)(int num_actual_args, +@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result, +@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo); +@ @ @ @ const size_t max_expected_args; +@ @ @ @ const size_t min_required_args; +@ @ @ @ awk_bool_t suppress_lint; +@ @ @ @ void *data; /* opaque pointer to any extra state */ @} awk_ext_func_t; @end example @@ -32818,42 +32838,95 @@ or an underscore, which may be followed by any number of letters, digits, and underscores. Letter case in function names is significant. -@item awk_value_t *(*function)(int num_actual_args, awk_value_t *result); +@item awk_value_t *(*const function)(int num_actual_args, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo); This is a pointer to the C function that provides the extension's functionality. The function must fill in @code{*result} with either a number -or a string. @command{gawk} takes ownership of any string memory. +or a string. +@c FIXME: Change to a scalar - number, string or regex once regex api stuff is merged. +@command{gawk} takes ownership of any string memory. As mentioned earlier, string memory @emph{must} come from one of @code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}. The @code{num_actual_args} argument tells the C function how many actual parameters were passed from the calling @command{awk} code. +The @code{finfo} parameter is a pointer to the @code{awk_ext_func_t} for +this function. The called function may access data within it as desired, or not. + The function must return the value of @code{result}. This is for the convenience of the calling code inside @command{gawk}. -@item size_t max_expected_args; +@item const size_t max_expected_args; This is the maximum number of arguments the function expects to receive. -Each extension function may decide what to do if the number of -arguments isn't what it expected. As with real @command{awk} functions, it -is likely OK to ignore extra arguments. This value does not affect -actual program execution. - -Extension functions should compare this value to the number of actual -arguments passed and possibly issue a lint warning if there is an -undesirable mismatch. Of course, if -@samp{--lint=fatal} is used, this would cause the program to exit. +If called with more arguments than this, and if lint checking has +been enabled, then @command{gawk} prints a warning message. For more +information, see the entry for @code{suppress_lint}, later in this list. + +@item const size_t min_required_args; +This is the minimum number of arguments the function expects to receive. +If called with fewer arguments, @command{gawk} prints a fatal error +message and exits. + +@item awk_bool_t suppress_lint; +This flag tells @command{gawk} not to print a lint message if lint +checking has been enabled and if more arguments were supplied in the call +than expected. An extension function can tell if @command{gawk} already +printed at least one such message by checking if @samp{num_actual_args > +finfo->max_expected_args}. If so, and the function does not want more +lint messages to be printed, it should set @code{finfo->suppress_lint} +to @code{awk_true}. + +@item void *data; +This is an opaque pointer to any data that an extension function may +wish to have available when called. Passing the @code{awk_ext_func_t} +structure to the extension function, and having this pointer available +in it enable writing a single C or C++ function that implements multiple +@command{awk}-level extension functions. @end table Once you have a record representing your extension function, you register it with @command{gawk} using this API function: @table @code -@item awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func); +@item awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func); This function returns true upon success, false otherwise. The @code{namespace} parameter is currently not used; you should pass in an empty string (@code{""}). The @code{func} pointer is the address of a @code{struct} representing your function, as just described. + +@command{gawk} does not modify what @code{func} points to, but the +extension function itself receives this pointer and can modify what it +points to, thus it is purposely not declared to be @code{const}. +@end table + +The combination of @code{min_required_args}, @code{max_expected_args}, +and @code{suppress_lint} may be confusing. Here is how you should +set things up. + +@table @asis +@item Any number of arguments is valid +Set @code{min_required_args} and @code{max_expected_args} to zero and +set @code{suppress_lint} to @code{awk_true}. + +@item A minimum number of arguments is required, no limit on maximum number of arguments +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to zero and +set @code{suppress_lint} to @code{awk_true}. + +@item A minium number of arguments is required, a maximum number is expected +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to the maximum expected. +Set @code{suppress_lint} to @code{awk_false}. + +@item A minum number of arguments is required, and no more than a maximum is allowed +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to the maximum expected. +Set @code{suppress_lint} to @code{awk_false}. +In your extension function, check that @code{num_actual_args} does not +exceed @code{f->max_expected_args}. If it does, issue a fatal error message. @end table @node Exit Callback Functions @@ -33398,6 +33471,7 @@ value type, as appropriate. This behavior is summarized in @float Table,table-value-types-returned @caption{API value types returned} +@c FIXME: This needs doing. @docbook <informaltable> <tgroup cols="6"> @@ -33473,6 +33547,7 @@ value type, as appropriate. This behavior is summarized in </informaltable> @end docbook +@c FIXME: This needs doing. @ifnotplaintext @ifnotdocbook @multitable @columnfractions .50 .50 @@ -33495,27 +33570,29 @@ value type, as appropriate. This behavior is summarized in @end ifnotplaintext @ifplaintext @example - +-------------------------------------------------+ - | Type of Actual Value: | - +------------+------------+-----------+-----------+ - | String | Number | Array | Undefined | -+-----------+-----------+------------+------------+-----------+-----------+ -| | String | String | String | False | False | -| |-----------+------------+------------+-----------+-----------+ -| | Number | Number if | Number | False | False | -| | | can be | | | | -| | | converted, | | | | -| | | else false | | | | -| |-----------+------------+------------+-----------+-----------+ -| Type | Array | False | False | Array | False | -| Requested |-----------+------------+------------+-----------+-----------+ -| | Scalar | Scalar | Scalar | False | False | -| |-----------+------------+------------+-----------+-----------+ -| | Undefined | String | Number | Array | Undefined | -| |-----------+------------+------------+-----------+-----------+ -| | Value | False | False | False | False | -| | cookie | | | | | -+-----------+-----------+------------+------------+-----------+-----------+ + +-------------------------------------------------------------+ + | Type of Actual Value: | + +------------+------------+-----------+-----------+-----------+ + | String | Number | Regex | Array | Undefined | ++-----------+-----------+------------+------------+-----------+-----------+-----------+ +| | String | String | String | String | false | false | +| +-----------+------------+------------+-----------+-----------+-----------+ +| | Number | Number if | Number | false | false | false | +| | | can be | | | | | +| | | converted, | | | | | +| | | else false | | | | | +| +-----------+------------+------------+-----------+-----------+-----------+ +| | Regex | false | false | Regex | false | false | +| +-----------+------------+------------+-----------+-----------+-----------+ +| Type | Array | false | false | false | Array | false | +| Requested +-----------+------------+------------+-----------+-----------+-----------+ +| | Scalar | Scalar | Scalar | Scalar | false | false | +| +-----------+------------+------------+-----------+-----------+-----------+ +| | Undefined | String | Number | Regex | Array | Undefined | +| +-----------+------------+------------+-----------+-----------+-----------+ +| | Value | false | false | false | false | false | +| | Cookie | | | | | | ++-----------+-----------+------------+------------+-----------+-----------+-----------+ @end example @end ifplaintext @end float @@ -33594,13 +33671,6 @@ An extension can look up the value of @command{gawk}'s special variables. However, with the exception of the @code{PROCINFO} array, an extension cannot change any of those variables. -@quotation CAUTION -It is possible for the lookup of @code{PROCINFO} to fail. This happens if -the @command{awk} program being run does not reference @code{PROCINFO}; -in this case, @command{gawk} doesn't bother to create the array and -populate it. -@end quotation - @node Symbol table by cookie @subsubsection Variable Access and Update by Cookie @@ -33622,7 +33692,7 @@ Return false if the value cannot be retrieved. @item awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value); Update the value associated with a scalar cookie. Return false if -the new value is not of type @code{AWK_STRING} or @code{AWK_NUMBER}. +the new value is not of type @code{AWK_STRING}, @code{AWK_REGEX}, or @code{AWK_NUMBER}. Here too, the predefined variables may not be updated. @end table @@ -33743,7 +33813,7 @@ is what the routines in this @value{SECTION} let you do. The functions are as f @table @code @item awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result); Create a cached string or numeric value from @code{value} for -efficient later assignment. Only values of type @code{AWK_NUMBER} +efficient later assignment. Only values of type @code{AWK_NUMBER}, @code{AWK_REGEX}, and @code{AWK_STRING} are allowed. Any other type is rejected. @code{AWK_UNDEFINED} could be allowed, but doing so would result in inferior performance. @@ -34486,10 +34556,10 @@ debugging: @float Table,gawk-api-version @caption{gawk API version constants} -@multitable @columnfractions .33 .33 .33 -@headitem API Version @tab C preprocessor define @tab enum constant -@item Major @tab gawk_api_major_version @tab GAWK_API_MAJOR_VERSION -@item Minor @tab gawk_api_minor_version @tab GAWK_API_MINOR_VERSION +@multitable {@b{API Version}} {@code{gawk_api_major_version}} {@code{GAWK_API_MAJOR_VERSION}} +@headitem API Version @tab C Preprocessor Define @tab enum constant +@item Major @tab @code{gawk_api_major_version} @tab @code{GAWK_API_MAJOR_VERSION} +@item Minor @tab @code{gawk_api_minor_version} @tab @code{GAWK_API_MINOR_VERSION} @end multitable @end float @@ -34508,10 +34578,10 @@ constant integers: @table @code @item api->major_version -The major version of the running @command{gawk} +The major version of the running @command{gawk}. @item api->minor_version -The minor version of the running @command{gawk} +The minor version of the running @command{gawk}. @end table It is up to the extension to decide if there are API incompatibilities. @@ -34584,7 +34654,7 @@ static awk_ext_id_t ext_id; static const char *ext_version = NULL; /* or @dots{} = "some string" */ static awk_ext_func_t func_table[] = @{ - @{ "name", do_name, 1 @}, + @{ "name", do_name, 1, 0, awk_false, NULL @}, /* @dots{} */ @}; @@ -34685,6 +34755,19 @@ If @code{ext_version} is not @code{NULL}, register the version string with @command{gawk}. @end enumerate + +@node Changes from API V1 +@subsection Changes From Version 1 of the API + +The current API is @emph{not} binary compatible with version 1 of the API. +You will have to recompile your extensions in order to use them with +the current version of @command{gawk}. + +Fortunately, at the possible expense of some compile-time warnings, the API remains +source-code--compatible with the previous API. The major differences are +the additional members in the @code{awk_ext_func_t} structure, and the +addition of the third argument to the C implementation function. + @node Finding Extensions @section How @command{gawk} Finds Extensions @cindex extension search path @@ -34925,17 +35008,12 @@ The second is a pointer to an @code{awk_value_t} structure, usually named /* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * -do_chdir(int nargs, awk_value_t *result) +do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused) @{ awk_value_t newdir; int ret = -1; assert(result != NULL); - - if (do_lint && nargs != 1) - lintwarn(ext_id, - _("chdir: called with incorrect number of arguments, " - "expecting 1")); @end example The @code{newdir} @@ -34944,8 +35022,8 @@ with @code{get_argument()}. Note that the first argument is numbered zero. If the argument is retrieved successfully, the function calls the -@code{chdir()} system call. If the @code{chdir()} fails, @code{ERRNO} -is updated: +@code{chdir()} system call. Otherwise, if the @code{chdir()} fails, +it updates @code{ERRNO}: @example if (get_argument(0, AWK_STRING, & newdir)) @{ @@ -35149,15 +35227,11 @@ is set to point to @code{stat()}, instead. Here is the @code{do_stat()} function, which starts with variable declarations and argument checking: -@ignore -Changed message for page breaking. Used to be: - "stat: called with incorrect number of arguments (%d), should be 2", -@end ignore @example /* do_stat --- provide a stat() function for gawk */ static awk_value_t * -do_stat(int nargs, awk_value_t *result) +do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused) @{ awk_value_t file_param, array_param; char *name; @@ -35168,13 +35242,6 @@ do_stat(int nargs, awk_value_t *result) int (*statfunc)(const char *path, struct stat *sbuf) = lstat; assert(result != NULL); - - if (nargs != 2 && nargs != 3) @{ - if (do_lint) - lintwarn(ext_id, - _("stat: called with wrong number of arguments")); - return make_number(-1, result); - @} @end example Then comes the actual work. First, the function gets the arguments. @@ -35242,11 +35309,9 @@ structures for loading each function into @command{gawk}: @example static awk_ext_func_t func_table[] = @{ - @{ "chdir", do_chdir, 1 @}, - @{ "stat", do_stat, 2 @}, -#ifndef __MINGW32__ - @{ "fts", do_fts, 3 @}, -#endif + @{ "chdir", do_chdir, 1, 1, awk_false, NULL @}, + @{ "stat", do_stat, 3, 2, awk_false, NULL @}, + @dots{} @}; @end example diff --git a/doc/gawktexi.in b/doc/gawktexi.in index fc43c520..c1674c11 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -928,6 +928,7 @@ particular records in a file and perform operations upon them. * Extension API Informational Variables:: Variables providing information about @command{gawk}'s invocation. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. * Finding Extensions:: How @command{gawk} finds compiled extensions. * Extension Example:: Example C code for an extension. @@ -31337,6 +31338,7 @@ This (rather large) @value{SECTION} describes the API in detail. redirections. * Extension API Variables:: Variables provided by the API. * Extension API Boilerplate:: Boilerplate code for using the API. +* Changes from API V1:: Changes from V1 of the API. @end menu @node Extension API Functions Introduction @@ -31854,8 +31856,13 @@ Extension functions are described by the following record: @example typedef struct awk_ext_func @{ @ @ @ @ const char *name; -@ @ @ @ awk_value_t *(*function)(int num_actual_args, awk_value_t *result); -@ @ @ @ size_t max_expected_args; +@ @ @ @ awk_value_t *(*const function)(int num_actual_args, +@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result, +@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo); +@ @ @ @ const size_t max_expected_args; +@ @ @ @ const size_t min_required_args; +@ @ @ @ awk_bool_t suppress_lint; +@ @ @ @ void *data; /* opaque pointer to any extra state */ @} awk_ext_func_t; @end example @@ -31873,42 +31880,95 @@ or an underscore, which may be followed by any number of letters, digits, and underscores. Letter case in function names is significant. -@item awk_value_t *(*function)(int num_actual_args, awk_value_t *result); +@item awk_value_t *(*const function)(int num_actual_args, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo); This is a pointer to the C function that provides the extension's functionality. The function must fill in @code{*result} with either a number -or a string. @command{gawk} takes ownership of any string memory. +or a string. +@c FIXME: Change to a scalar - number, string or regex once regex api stuff is merged. +@command{gawk} takes ownership of any string memory. As mentioned earlier, string memory @emph{must} come from one of @code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}. The @code{num_actual_args} argument tells the C function how many actual parameters were passed from the calling @command{awk} code. +The @code{finfo} parameter is a pointer to the @code{awk_ext_func_t} for +this function. The called function may access data within it as desired, or not. + The function must return the value of @code{result}. This is for the convenience of the calling code inside @command{gawk}. -@item size_t max_expected_args; +@item const size_t max_expected_args; This is the maximum number of arguments the function expects to receive. -Each extension function may decide what to do if the number of -arguments isn't what it expected. As with real @command{awk} functions, it -is likely OK to ignore extra arguments. This value does not affect -actual program execution. - -Extension functions should compare this value to the number of actual -arguments passed and possibly issue a lint warning if there is an -undesirable mismatch. Of course, if -@samp{--lint=fatal} is used, this would cause the program to exit. +If called with more arguments than this, and if lint checking has +been enabled, then @command{gawk} prints a warning message. For more +information, see the entry for @code{suppress_lint}, later in this list. + +@item const size_t min_required_args; +This is the minimum number of arguments the function expects to receive. +If called with fewer arguments, @command{gawk} prints a fatal error +message and exits. + +@item awk_bool_t suppress_lint; +This flag tells @command{gawk} not to print a lint message if lint +checking has been enabled and if more arguments were supplied in the call +than expected. An extension function can tell if @command{gawk} already +printed at least one such message by checking if @samp{num_actual_args > +finfo->max_expected_args}. If so, and the function does not want more +lint messages to be printed, it should set @code{finfo->suppress_lint} +to @code{awk_true}. + +@item void *data; +This is an opaque pointer to any data that an extension function may +wish to have available when called. Passing the @code{awk_ext_func_t} +structure to the extension function, and having this pointer available +in it enable writing a single C or C++ function that implements multiple +@command{awk}-level extension functions. @end table Once you have a record representing your extension function, you register it with @command{gawk} using this API function: @table @code -@item awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func); +@item awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func); This function returns true upon success, false otherwise. The @code{namespace} parameter is currently not used; you should pass in an empty string (@code{""}). The @code{func} pointer is the address of a @code{struct} representing your function, as just described. + +@command{gawk} does not modify what @code{func} points to, but the +extension function itself receives this pointer and can modify what it +points to, thus it is purposely not declared to be @code{const}. +@end table + +The combination of @code{min_required_args}, @code{max_expected_args}, +and @code{suppress_lint} may be confusing. Here is how you should +set things up. + +@table @asis +@item Any number of arguments is valid +Set @code{min_required_args} and @code{max_expected_args} to zero and +set @code{suppress_lint} to @code{awk_true}. + +@item A minimum number of arguments is required, no limit on maximum number of arguments +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to zero and +set @code{suppress_lint} to @code{awk_true}. + +@item A minium number of arguments is required, a maximum number is expected +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to the maximum expected. +Set @code{suppress_lint} to @code{awk_false}. + +@item A minum number of arguments is required, and no more than a maximum is allowed +Set @code{min_required_args} to the minimum required. Set +@code{max_expected_args} to the maximum expected. +Set @code{suppress_lint} to @code{awk_false}. +In your extension function, check that @code{num_actual_args} does not +exceed @code{f->max_expected_args}. If it does, issue a fatal error message. @end table @node Exit Callback Functions @@ -32652,13 +32712,6 @@ An extension can look up the value of @command{gawk}'s special variables. However, with the exception of the @code{PROCINFO} array, an extension cannot change any of those variables. -@quotation CAUTION -It is possible for the lookup of @code{PROCINFO} to fail. This happens if -the @command{awk} program being run does not reference @code{PROCINFO}; -in this case, @command{gawk} doesn't bother to create the array and -populate it. -@end quotation - @node Symbol table by cookie @subsubsection Variable Access and Update by Cookie @@ -33550,7 +33603,7 @@ debugging: @float Table,gawk-api-version @caption{gawk API version constants} -@multitable @columnfractions .20 .33 .33 +@multitable {@b{API Version}} {@code{gawk_api_major_version}} {@code{GAWK_API_MAJOR_VERSION}} @headitem API Version @tab C Preprocessor Define @tab enum constant @item Major @tab @code{gawk_api_major_version} @tab @code{GAWK_API_MAJOR_VERSION} @item Minor @tab @code{gawk_api_minor_version} @tab @code{GAWK_API_MINOR_VERSION} @@ -33572,10 +33625,10 @@ constant integers: @table @code @item api->major_version -The major version of the running @command{gawk} +The major version of the running @command{gawk}. @item api->minor_version -The minor version of the running @command{gawk} +The minor version of the running @command{gawk}. @end table It is up to the extension to decide if there are API incompatibilities. @@ -33648,7 +33701,7 @@ static awk_ext_id_t ext_id; static const char *ext_version = NULL; /* or @dots{} = "some string" */ static awk_ext_func_t func_table[] = @{ - @{ "name", do_name, 1 @}, + @{ "name", do_name, 1, 0, awk_false, NULL @}, /* @dots{} */ @}; @@ -33749,6 +33802,19 @@ If @code{ext_version} is not @code{NULL}, register the version string with @command{gawk}. @end enumerate + +@node Changes from API V1 +@subsection Changes From Version 1 of the API + +The current API is @emph{not} binary compatible with version 1 of the API. +You will have to recompile your extensions in order to use them with +the current version of @command{gawk}. + +Fortunately, at the possible expense of some compile-time warnings, the API remains +source-code--compatible with the previous API. The major differences are +the additional members in the @code{awk_ext_func_t} structure, and the +addition of the third argument to the C implementation function. + @node Finding Extensions @section How @command{gawk} Finds Extensions @cindex extension search path @@ -33989,17 +34055,12 @@ The second is a pointer to an @code{awk_value_t} structure, usually named /* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * -do_chdir(int nargs, awk_value_t *result) +do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused) @{ awk_value_t newdir; int ret = -1; assert(result != NULL); - - if (do_lint && nargs != 1) - lintwarn(ext_id, - _("chdir: called with incorrect number of arguments, " - "expecting 1")); @end example The @code{newdir} @@ -34008,8 +34069,8 @@ with @code{get_argument()}. Note that the first argument is numbered zero. If the argument is retrieved successfully, the function calls the -@code{chdir()} system call. If the @code{chdir()} fails, @code{ERRNO} -is updated: +@code{chdir()} system call. Otherwise, if the @code{chdir()} fails, +it updates @code{ERRNO}: @example if (get_argument(0, AWK_STRING, & newdir)) @{ @@ -34213,15 +34274,11 @@ is set to point to @code{stat()}, instead. Here is the @code{do_stat()} function, which starts with variable declarations and argument checking: -@ignore -Changed message for page breaking. Used to be: - "stat: called with incorrect number of arguments (%d), should be 2", -@end ignore @example /* do_stat --- provide a stat() function for gawk */ static awk_value_t * -do_stat(int nargs, awk_value_t *result) +do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused) @{ awk_value_t file_param, array_param; char *name; @@ -34232,13 +34289,6 @@ do_stat(int nargs, awk_value_t *result) int (*statfunc)(const char *path, struct stat *sbuf) = lstat; assert(result != NULL); - - if (nargs != 2 && nargs != 3) @{ - if (do_lint) - lintwarn(ext_id, - _("stat: called with wrong number of arguments")); - return make_number(-1, result); - @} @end example Then comes the actual work. First, the function gets the arguments. @@ -34306,11 +34356,9 @@ structures for loading each function into @command{gawk}: @example static awk_ext_func_t func_table[] = @{ - @{ "chdir", do_chdir, 1 @}, - @{ "stat", do_stat, 2 @}, -#ifndef __MINGW32__ - @{ "fts", do_fts, 3 @}, -#endif + @{ "chdir", do_chdir, 1, 1, awk_false, NULL @}, + @{ "stat", do_stat, 3, 2, awk_false, NULL @}, + @dots{} @}; @end example @@ -136,7 +136,7 @@ make_builtin(const awk_ext_func_t *funcinfo) b = bcalloc(Op_symbol, 1, 0); b->extfunc = funcinfo->function; - b->expr_count = count; + b->c_func = (awk_ext_func_t *) funcinfo; /* NB: extension sub must return something */ diff --git a/extension/ChangeLog b/extension/ChangeLog index f826e540..9c647f05 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,46 @@ +2016-12-16 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c: Update func_table again. + +2016-12-14 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c: Update do_xxx to match new API. Update func_table. + * fnmatch.c: Ditto. + * fork.c: Ditto. + * inplace.c: Ditto. + * ordchr.c: Ditto. + * readdir.c: Ditto. + * readfile.c: Ditto. + * revoutput.c: Ditto. + * revtwoway.c: Ditto. + * rwarray.c: Ditto. + * rwarray0.c: Ditto. + * testext.c: Ditto. + * time.c: Ditto. + +2016-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c (func_table): Adjust ordering of min and max + for stat. + +2016-12-06 Arnold D. Robbins <arnold@skeeve.com> + + Add minimum required and maximum expected number of arguments + to the API. + + * filefuncs.c: Update with max expected value. Remove lint + checks since that's now done by gawk. + * fnmatch.c: Ditto. + * fork.c: Ditto. + * inplace.c: Ditto. + * ordchr.c: Ditto. + * readdir.c: Ditto. + * readfile.c: Ditto. + * rwarray.c: Ditto. + * rwarray0.c: Ditto. + * testext.c: Ditto. + * time.c: Ditto. + 2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com> * rwarray.c: Adjust to read and write strnum values. diff --git a/extension/filefuncs.c b/extension/filefuncs.c index a074de53..394de504 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -153,16 +153,13 @@ int plugin_is_GPL_compatible; /* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * -do_chdir(int nargs, awk_value_t *result) +do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t newdir; int ret = -1; assert(result != NULL); - if (do_lint && nargs != 1) - lintwarn(ext_id, _("chdir: called with incorrect number of arguments, expecting 1")); - if (get_argument(0, AWK_STRING, & newdir)) { ret = chdir(newdir.str_value.str); if (ret < 0) @@ -461,7 +458,7 @@ fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf) /* do_stat --- provide a stat() function for gawk */ static awk_value_t * -do_stat(int nargs, awk_value_t *result) +do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t file_param, array_param; char *name; @@ -472,12 +469,6 @@ do_stat(int nargs, awk_value_t *result) assert(result != NULL); - if (nargs != 2 && nargs != 3) { - if (do_lint) - lintwarn(ext_id, _("stat: called with wrong number of arguments")); - return make_number(-1, result); - } - /* file is first arg, array to hold results is second */ if ( ! get_argument(0, AWK_STRING, & file_param) || ! get_argument(1, AWK_ARRAY, & array_param)) { @@ -512,7 +503,7 @@ do_stat(int nargs, awk_value_t *result) /* do_statvfs --- provide a statvfs() function for gawk */ static awk_value_t * -do_statvfs(int nargs, awk_value_t *result) +do_statvfs(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t file_param, array_param; char *name; @@ -522,12 +513,6 @@ do_statvfs(int nargs, awk_value_t *result) assert(result != NULL); - if (nargs != 2) { - if (do_lint) - lintwarn(ext_id, _("statvfs: called with wrong number of arguments")); - return make_number(-1, result); - } - /* file is first arg, array to hold results is second */ if ( ! get_argument(0, AWK_STRING, & file_param) || ! get_argument(1, AWK_ARRAY, & array_param)) { @@ -614,7 +599,7 @@ init_filefuncs(void) */ static awk_value_t * -do_fts(int nargs, awk_value_t *result) +do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused) { fatal(ext_id, _("fts is not supported on this system")); @@ -829,7 +814,7 @@ process(FTS *heirarchy, awk_array_t destarray, int seedot) */ static awk_value_t * -do_fts(int nargs, awk_value_t *result) +do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t pathlist, flagval, dest; awk_flat_array_t *path_array = NULL; @@ -845,7 +830,7 @@ do_fts(int nargs, awk_value_t *result) assert(result != NULL); fts_errors = 0; /* ensure a fresh start */ - if (do_lint && nargs != 3) + if (nargs > 3) lintwarn(ext_id, _("fts: called with incorrect number of arguments, expecting 3")); if (! get_argument(0, AWK_ARRAY, & pathlist)) { @@ -928,13 +913,13 @@ out: #endif /* ! __MINGW32__ */ static awk_ext_func_t func_table[] = { - { "chdir", do_chdir, 1 }, - { "stat", do_stat, 3 }, + { "chdir", do_chdir, 1, 1, awk_false, NULL }, + { "stat", do_stat, 3, 2, awk_false, NULL }, #ifndef __MINGW32__ - { "fts", do_fts, 3 }, + { "fts", do_fts, 3, 3, awk_false, NULL }, #endif #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) - { "statvfs", do_statvfs, 2 }, + { "statvfs", do_statvfs, 2, 2, awk_false, NULL }, #endif }; diff --git a/extension/fnmatch.c b/extension/fnmatch.c index f5fb02c6..5382e4bc 100644 --- a/extension/fnmatch.c +++ b/extension/fnmatch.c @@ -95,7 +95,7 @@ int plugin_is_GPL_compatible; /* do_fnmatch --- implement the fnmatch interface */ static awk_value_t * -do_fnmatch(int nargs, awk_value_t *result) +do_fnmatch(int nargs, awk_value_t *result, struct awk_ext_func *unused) { #ifdef HAVE_FNMATCH_H static int flags_mask = @@ -107,13 +107,8 @@ do_fnmatch(int nargs, awk_value_t *result) int int_flags, retval; make_number(-1.0, result); /* default return */ -#ifdef HAVE_FNMATCH - if (nargs < 3) { - warning(ext_id, _("fnmatch: called with less than three arguments")); - goto out; - } else if (do_lint && nargs > 3) - lintwarn(ext_id, _("fnmatch: called with more than three arguments")); +#ifdef HAVE_FNMATCH if (! get_argument(0, AWK_STRING, & pattern)) { warning(ext_id, _("fnmatch: could not get first argument")); goto out; @@ -199,7 +194,7 @@ init_fnmatch(void) } static awk_ext_func_t func_table[] = { - { "fnmatch", do_fnmatch, 3 }, + { "fnmatch", do_fnmatch, 3, 3, awk_false, NULL }, }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/fork.c b/extension/fork.c index 82593b7f..823506dd 100644 --- a/extension/fork.c +++ b/extension/fork.c @@ -71,15 +71,12 @@ array_set_numeric(awk_array_t array, const char *sub, double num) /* do_fork --- provide dynamically loaded fork() builtin for gawk */ static awk_value_t * -do_fork(int nargs, awk_value_t *result) +do_fork(int nargs, awk_value_t *result, struct awk_ext_func *unused) { int ret = -1; assert(result != NULL); - if (do_lint && nargs > 0) - lintwarn(ext_id, _("fork: called with too many arguments")); - ret = fork(); if (ret < 0) @@ -106,7 +103,7 @@ do_fork(int nargs, awk_value_t *result) /* do_waitpid --- provide dynamically loaded waitpid() builtin for gawk */ static awk_value_t * -do_waitpid(int nargs, awk_value_t *result) +do_waitpid(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t pid; int ret = -1; @@ -114,16 +111,12 @@ do_waitpid(int nargs, awk_value_t *result) assert(result != NULL); - if (do_lint && nargs > 1) - lintwarn(ext_id, _("waitpid: called with too many arguments")); - if (get_argument(0, AWK_NUMBER, &pid)) { options = WNOHANG|WUNTRACED; ret = waitpid(pid.num_value, NULL, options); if (ret < 0) update_ERRNO_int(errno); - } else if (do_lint) - lintwarn(ext_id, _("wait: called with no arguments")); + } /* Set the return value */ return make_number(ret, result); @@ -133,15 +126,12 @@ do_waitpid(int nargs, awk_value_t *result) /* do_wait --- provide dynamically loaded wait() builtin for gawk */ static awk_value_t * -do_wait(int nargs, awk_value_t *result) +do_wait(int nargs, awk_value_t *result, struct awk_ext_func *unused) { int ret; assert(result != NULL); - if (do_lint && nargs > 0) - lintwarn(ext_id, _("wait: called with too many arguments")); - ret = wait(NULL); if (ret < 0) update_ERRNO_int(errno); @@ -151,9 +141,9 @@ do_wait(int nargs, awk_value_t *result) } static awk_ext_func_t func_table[] = { - { "fork", do_fork, 0 }, - { "waitpid", do_waitpid, 1 }, - { "wait", do_wait, 0 }, + { "fork", do_fork, 0, 0, awk_false, NULL }, + { "waitpid", do_waitpid, 1, 1, awk_false, NULL }, + { "wait", do_wait, 0, 0, awk_false, NULL }, }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/inplace.c b/extension/inplace.c index 26c37922..5457287f 100644 --- a/extension/inplace.c +++ b/extension/inplace.c @@ -118,7 +118,7 @@ invalid_filename(const awk_string_t *filename) /* do_inplace_begin --- start in-place editing */ static awk_value_t * -do_inplace_begin(int nargs, awk_value_t *result) +do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename; struct stat sbuf; @@ -201,7 +201,7 @@ do_inplace_begin(int nargs, awk_value_t *result) /* do_inplace_end --- finish in-place editing */ static awk_value_t * -do_inplace_end(int nargs, awk_value_t *result) +do_inplace_end(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, suffix; @@ -262,8 +262,8 @@ do_inplace_end(int nargs, awk_value_t *result) } static awk_ext_func_t func_table[] = { - { "inplace_begin", do_inplace_begin, 2 }, - { "inplace_end", do_inplace_end, 2 }, + { "inplace_begin", do_inplace_begin, 2, 2, awk_false, NULL }, + { "inplace_end", do_inplace_end, 2, 2, awk_false, NULL }, }; static awk_bool_t init_inplace(void) diff --git a/extension/ordchr.c b/extension/ordchr.c index 4f9cd616..c7451f6d 100644 --- a/extension/ordchr.c +++ b/extension/ordchr.c @@ -58,24 +58,17 @@ int plugin_is_GPL_compatible; /* do_ord --- return numeric value of first char of string */ static awk_value_t * -do_ord(int nargs, awk_value_t *result) +do_ord(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t str; double ret = -1; assert(result != NULL); - if (do_lint && nargs > 1) - lintwarn(ext_id, _("ord: called with too many arguments")); - if (get_argument(0, AWK_STRING, & str)) { ret = str.str_value.str[0]; - } else if (do_lint) { - if (nargs == 0) - lintwarn(ext_id, _("ord: called with no arguments")); - else - lintwarn(ext_id, _("ord: called with inappropriate argument(s)")); - } + } else if (do_lint) + lintwarn(ext_id, _("ord: called with inappropriate argument(s)")); /* Set the return value */ return make_number(ret, result); @@ -84,7 +77,7 @@ do_ord(int nargs, awk_value_t *result) /* do_chr --- turn numeric value into a string */ static awk_value_t * -do_chr(int nargs, awk_value_t *result) +do_chr(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t num; unsigned int ret = 0; @@ -95,29 +88,22 @@ do_chr(int nargs, awk_value_t *result) assert(result != NULL); - if (do_lint && nargs > 1) - lintwarn(ext_id, _("chr: called with too many arguments")); - if (get_argument(0, AWK_NUMBER, & num)) { val = num.num_value; ret = val; /* convert to int */ ret &= 0xff; str[0] = ret; str[1] = '\0'; - } else if (do_lint) { - if (nargs == 0) - lintwarn(ext_id, _("chr: called with no arguments")); - else - lintwarn(ext_id, _("chr: called with inappropriate argument(s)")); - } + } else if (do_lint) + lintwarn(ext_id, _("chr: called with inappropriate argument(s)")); /* Set the return value */ return make_const_string(str, 1, result); } static awk_ext_func_t func_table[] = { - { "ord", do_ord, 1 }, - { "chr", do_chr, 1 }, + { "ord", do_ord, 1, 1, awk_false, NULL }, + { "chr", do_chr, 1, 1, awk_false, NULL }, }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/readdir.c b/extension/readdir.c index 6106a44b..39acba68 100644 --- a/extension/readdir.c +++ b/extension/readdir.c @@ -316,7 +316,7 @@ init_readdir() } static awk_ext_func_t func_table[] = { - { NULL, NULL, 0 } + { NULL, NULL, 0, 0, awk_false, NULL } }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/readfile.c b/extension/readfile.c index fbe25748..b453da21 100644 --- a/extension/readfile.c +++ b/extension/readfile.c @@ -98,7 +98,7 @@ done: /* do_readfile --- read a file into memory */ static awk_value_t * -do_readfile(int nargs, awk_value_t *result) +do_readfile(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename; int ret; @@ -109,9 +109,6 @@ do_readfile(int nargs, awk_value_t *result) assert(result != NULL); make_null_string(result); /* default return value */ - if (do_lint && nargs > 1) - lintwarn(ext_id, _("readfile: called with too many arguments")); - unset_ERRNO(); if (get_argument(0, AWK_STRING, &filename)) { @@ -134,7 +131,7 @@ do_readfile(int nargs, awk_value_t *result) make_malloced_string(text, sbuf.st_size, result); goto done; } else if (do_lint) - lintwarn(ext_id, _("readfile: called with no arguments")); + lintwarn(ext_id, _("readfile: called with wrong kind of argument")); done: /* Set the return value */ @@ -241,7 +238,7 @@ init_readfile() } static awk_ext_func_t func_table[] = { - { "readfile", do_readfile, 1 }, + { "readfile", do_readfile, 1, 1, awk_false, NULL }, }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/revoutput.c b/extension/revoutput.c index 84d0aaa5..5862ed6e 100644 --- a/extension/revoutput.c +++ b/extension/revoutput.c @@ -134,7 +134,7 @@ init_revoutput() } static awk_ext_func_t func_table[] = { - { NULL, NULL, 0 } + { NULL, NULL, 0, 0, awk_false, NULL } }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/revtwoway.c b/extension/revtwoway.c index 82fabb2b..ac4e22cf 100644 --- a/extension/revtwoway.c +++ b/extension/revtwoway.c @@ -336,7 +336,7 @@ init_revtwoway() } static awk_ext_func_t func_table[] = { - { NULL, NULL, 0 } + { NULL, NULL, 0, 0, awk_false, NULL } }; /* define the dl_load function using the boilerplate macro */ diff --git a/extension/rwarray.c b/extension/rwarray.c index 5b9fd5de..186dac0f 100644 --- a/extension/rwarray.c +++ b/extension/rwarray.c @@ -99,7 +99,7 @@ static awk_bool_t read_value(FILE *fp, awk_value_t *value); /* do_writea --- write an array */ static awk_value_t * -do_writea(int nargs, awk_value_t *result) +do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, array; FILE *fp = NULL; @@ -109,9 +109,6 @@ do_writea(int nargs, awk_value_t *result) assert(result != NULL); make_number(0.0, result); - if (do_lint && nargs > 2) - lintwarn(ext_id, _("writea: called with too many arguments")); - if (nargs < 2) goto out; @@ -269,7 +266,7 @@ write_value(FILE *fp, awk_value_t *val) /* do_reada --- read an array */ static awk_value_t * -do_reada(int nargs, awk_value_t *result) +do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, array; FILE *fp = NULL; @@ -280,9 +277,6 @@ do_reada(int nargs, awk_value_t *result) assert(result != NULL); make_number(0.0, result); - if (do_lint && nargs > 2) - lintwarn(ext_id, _("reada: called with too many arguments")); - if (nargs < 2) goto out; @@ -500,8 +494,8 @@ read_value(FILE *fp, awk_value_t *value) } static awk_ext_func_t func_table[] = { - { "writea", do_writea, 2 }, - { "reada", do_reada, 2 }, + { "writea", do_writea, 2, 2, awk_false, NULL }, + { "reada", do_reada, 2, 2, awk_false, NULL }, }; diff --git a/extension/rwarray0.c b/extension/rwarray0.c index 00289cad..faa73783 100644 --- a/extension/rwarray0.c +++ b/extension/rwarray0.c @@ -95,7 +95,7 @@ static awk_bool_t read_value(int fd, awk_value_t *value); /* do_writea --- write an array */ static awk_value_t * -do_writea(int nargs, awk_value_t *result) +do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, array; int fd = -1; @@ -105,9 +105,6 @@ do_writea(int nargs, awk_value_t *result) assert(result != NULL); make_number(0.0, result); - if (do_lint && nargs > 2) - lintwarn(ext_id, _("writea: called with too many arguments")); - if (nargs < 2) goto out; @@ -250,7 +247,7 @@ write_value(int fd, awk_value_t *val) /* do_reada --- read an array */ static awk_value_t * -do_reada(int nargs, awk_value_t *result) +do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, array; int fd = -1; @@ -261,9 +258,6 @@ do_reada(int nargs, awk_value_t *result) assert(result != NULL); make_number(0.0, result); - if (do_lint && nargs > 2) - lintwarn(ext_id, _("reada: called with too many arguments")); - if (nargs < 2) goto out; @@ -465,8 +459,8 @@ read_value(int fd, awk_value_t *value) } static awk_ext_func_t func_table[] = { - { "writea", do_writea, 2 }, - { "reada", do_reada, 2 }, + { "writea", do_writea, 2, 2, awk_false, NULL }, + { "reada", do_reada, 2, 2, awk_false, NULL }, }; diff --git a/extension/testext.c b/extension/testext.c index 9216d64a..bf342182 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -107,7 +107,7 @@ BEGIN { } */ static awk_value_t * -dump_array_and_delete(int nargs, awk_value_t *result) +dump_array_and_delete(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t value, value2, value3; awk_flat_array_t *flat_array; @@ -201,7 +201,7 @@ BEGIN { */ static awk_value_t * -try_modify_environ(int nargs, awk_value_t *result) +try_modify_environ(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t value, index, newvalue; awk_flat_array_t *flat_array; @@ -290,7 +290,7 @@ BEGIN { */ static awk_value_t * -var_test(int nargs, awk_value_t *result) +var_test(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t value, value2; awk_value_t *valp; @@ -357,7 +357,7 @@ BEGIN { } */ static awk_value_t * -test_errno(int nargs, awk_value_t *result) +test_errno(int nargs, awk_value_t *result, struct awk_ext_func *unused) { assert(result != NULL); make_number(0.0, result); @@ -386,7 +386,7 @@ BEGIN { } */ static awk_value_t * -test_deferred(int nargs, awk_value_t *result) +test_deferred(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t arr; awk_value_t index, value; @@ -465,7 +465,7 @@ BEGIN { */ static awk_value_t * -test_array_size(int nargs, awk_value_t *result) +test_array_size(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t value; size_t count = 0; @@ -529,7 +529,7 @@ BEGIN { } */ static awk_value_t * -test_array_elem(int nargs, awk_value_t *result) +test_array_elem(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t array, index, index2, value; @@ -617,7 +617,7 @@ BEGIN { */ static awk_value_t * -test_array_param(int nargs, awk_value_t *result) +test_array_param(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t new_array; awk_value_t arg0; @@ -660,7 +660,7 @@ BEGIN { } */ static awk_value_t * -print_do_lint(int nargs, awk_value_t *result) +print_do_lint(int nargs, awk_value_t *result, struct awk_ext_func *unused) { assert(result != NULL); make_number(0.0, result); @@ -696,7 +696,7 @@ BEGIN { /* test_scalar --- test scalar cookie */ static awk_value_t * -test_scalar(int nargs, awk_value_t *result) +test_scalar(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t new_value, new_value2; awk_value_t the_scalar; @@ -743,7 +743,7 @@ BEGIN { /* test_scalar_reserved --- test scalar cookie on special variable */ static awk_value_t * -test_scalar_reserved(int nargs, awk_value_t *result) +test_scalar_reserved(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t new_value; awk_value_t the_scalar; @@ -796,7 +796,7 @@ BEGIN { /* test_indirect_vars --- test that access to NR, NF, get correct vales */ static awk_value_t * -test_indirect_vars(int nargs, awk_value_t *result) +test_indirect_vars(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t value; char *name = "NR"; @@ -844,7 +844,7 @@ BEGIN { /* test_get_file --- test that we can create a file */ static awk_value_t * -test_get_file(int nargs, awk_value_t *result) +test_get_file(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, alias; int fd; @@ -882,7 +882,7 @@ test_get_file(int nargs, awk_value_t *result) /* do_get_file --- provide access to get_file API */ static awk_value_t * -do_get_file(int nargs, awk_value_t *result) +do_get_file(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t filename, filetype, fd, res; const awk_input_buf_t *ibuf; @@ -1024,20 +1024,20 @@ static void at_exit2(void *data, int exit_status) } 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 }, - { "test_array_param", test_array_param, 1 }, - { "print_do_lint", print_do_lint, 0 }, - { "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 }, + { "dump_array_and_delete", dump_array_and_delete, 2, 2, awk_false, NULL }, + { "try_modify_environ", try_modify_environ, 0, 0, awk_false, NULL }, + { "var_test", var_test, 1, 1, awk_false, NULL }, + { "test_deferred", test_deferred, 0, 0, awk_false, NULL }, + { "test_errno", test_errno, 0, 0, awk_false, NULL }, + { "test_array_size", test_array_size, 1, 1, awk_false, NULL }, + { "test_array_elem", test_array_elem, 2, 2, awk_false, NULL }, + { "test_array_param", test_array_param, 1, 1, awk_false, NULL }, + { "print_do_lint", print_do_lint, 0, 0, awk_false, NULL }, + { "test_scalar", test_scalar, 1, 1, awk_false, NULL }, + { "test_scalar_reserved", test_scalar_reserved, 0, 0, awk_false, NULL }, + { "test_indirect_vars", test_indirect_vars, 0, 0, awk_false, NULL }, + { "test_get_file", test_get_file, 2, 2, awk_false, NULL }, + { "get_file", do_get_file, 4, 4, awk_false, NULL }, }; /* init_testext --- additional initialization function */ diff --git a/extension/time.c b/extension/time.c index e6b2b39f..01be7784 100644 --- a/extension/time.c +++ b/extension/time.c @@ -103,15 +103,12 @@ int plugin_is_GPL_compatible; * on the platform */ static awk_value_t * -do_gettimeofday(int nargs, awk_value_t *result) +do_gettimeofday(int nargs, awk_value_t *result, struct awk_ext_func *unused) { double curtime; assert(result != NULL); - if (do_lint && nargs > 0) - lintwarn(ext_id, _("gettimeofday: ignoring arguments")); - #if defined(HAVE_GETTIMEOFDAY) { struct timeval tv; @@ -153,7 +150,7 @@ do_gettimeofday(int nargs, awk_value_t *result) * did not complete successfully (perhaps interrupted) */ static awk_value_t * -do_sleep(int nargs, awk_value_t *result) +do_sleep(int nargs, awk_value_t *result, struct awk_ext_func *unused) { awk_value_t num; double secs; @@ -161,9 +158,6 @@ do_sleep(int nargs, awk_value_t *result) assert(result != NULL); - if (do_lint && nargs > 1) - lintwarn(ext_id, _("sleep: called with too many arguments")); - if (! get_argument(0, AWK_NUMBER, &num)) { update_ERRNO_string(_("sleep: missing required numeric argument")); return make_number(-1, result); @@ -212,8 +206,8 @@ do_sleep(int nargs, awk_value_t *result) } static awk_ext_func_t func_table[] = { - { "gettimeofday", do_gettimeofday, 0 }, - { "sleep", do_sleep, 1 }, + { "gettimeofday", do_gettimeofday, 0, 0, awk_false, NULL }, + { "sleep", do_sleep, 1, 1, awk_false, NULL }, }; /* define the dl_load function using the boilerplate macro */ @@ -335,7 +335,7 @@ api_unset_ERRNO(awk_ext_id_t id) static awk_bool_t api_add_ext_func(awk_ext_id_t id, const char *namespace, - const awk_ext_func_t *func) + awk_ext_func_t *func) { (void) id; (void) namespace; @@ -260,8 +260,8 @@ typedef struct awk_two_way_processor { awk_const struct awk_two_way_processor *awk_const next; /* for use by gawk */ } awk_two_way_processor_t; -#define gawk_api_major_version 1 -#define gawk_api_minor_version 2 +#define gawk_api_major_version 2 +#define gawk_api_minor_version 0 /* Current version of the API. */ enum { @@ -380,15 +380,26 @@ typedef struct awk_flat_array { * Each extension function may decide what to do if the number of * arguments isn't what it expected. Following awk functions, it * is likely OK to ignore extra arguments. - - * Note that the 'max_expected_args' value should be used by the - * extension function itself only to trigger a lint warning if more - * arguments are passed to the function. + * + * 'min_required_args' indicates how many arguments MUST be passed. + * The API will throw a fatal error if not enough are passed. + * + * 'max_expected_args' is more benign; if more than that are passed, + * the API prints a lint message (IFF lint is enabled, of course). + * + * In any case, the extension function itself need not compare the + * actual number of arguments passed to those two values if it does + * not want to. */ typedef struct awk_ext_func { const char *name; - awk_value_t *(*function)(int num_actual_args, awk_value_t *result); - size_t max_expected_args; + awk_value_t *(*const function)(int num_actual_args, + awk_value_t *result, + struct awk_ext_func *finfo); + const size_t max_expected_args; + const size_t min_required_args; + awk_bool_t suppress_lint; + void *data; /* opaque pointer to any extra state */ } awk_ext_func_t; typedef void *awk_ext_id_t; /* opaque type for extension id */ @@ -421,9 +432,14 @@ typedef struct gawk_api { /* Next, registration functions: */ - /* Add a function to the interpreter, returns true upon success */ + /* + * Add a function to the interpreter, returns true upon success. + * Gawk does not modify what func points to, but the extension + * function itself receives this pointer and can modify what it + * points to, thus it's not const. + */ awk_bool_t (*api_add_ext_func)(awk_ext_id_t id, const char *namespace, - const awk_ext_func_t *func); + awk_ext_func_t *func); /* Register an input parser; for opening files read-only */ void (*api_register_input_parser)(awk_ext_id_t id, diff --git a/interpret.h b/interpret.h index da8e0604..1399e720 100644 --- a/interpret.h +++ b/interpret.h @@ -955,11 +955,22 @@ arrayfor: case Op_ext_builtin: { - int arg_count = pc->expr_count; + size_t arg_count = pc->expr_count; + awk_ext_func_t *f = pc[1].c_func; + size_t min_req = f->min_required_args; + size_t max_expect = f->max_expected_args; awk_value_t result; + if (arg_count < min_req) + fatal(_("%s: called with %lu arguments, expecting at least %lu"), + pc[1].func_name, arg_count, min_req); + + if (do_lint && ! f->suppress_lint && arg_count > max_expect) + lintwarn(_("%s: called with %lu arguments, expecting no more than %lu"), + pc[1].func_name, arg_count, max_expect); + PUSH_CODE(pc); - r = awk_value_to_node(pc->extfunc(arg_count, & result)); + r = awk_value_to_node(pc->extfunc(arg_count, & result, f)); (void) POP_CODE(); while (arg_count-- > 0) { t1 = POP(); @@ -1093,7 +1104,7 @@ match_re: npc[0].expr_count = arg_count; /* actual argument count */ npc[1] = pc[1]; npc[1].func_name = fname; /* name of the builtin */ - npc[1].expr_count = bc->expr_count; /* defined max # of arguments */ + npc[1].c_func = bc->c_func; ni = npc; JUMPTO(ni); } else @@ -1129,9 +1140,9 @@ match_re: assert(bc->opcode == Op_symbol); pc->opcode = Op_ext_builtin; /* self modifying code */ pc->extfunc = bc->extfunc; - pc->expr_count = arg_count; /* actual argument count */ + pc->expr_count = arg_count; /* actual argument count */ (pc + 1)->func_name = fname; /* name of the builtin */ - (pc + 1)->expr_count = bc->expr_count; /* defined max # of arguments */ + (pc + 1)->c_func = bc->c_func; /* min and max args */ ni = pc; JUMPTO(ni); } |