diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/gawk.info | 205 | ||||
-rw-r--r-- | doc/gawk.texi | 34 | ||||
-rw-r--r-- | doc/gawktexi.in | 34 | ||||
-rw-r--r-- | doc/wordlist | 2 | ||||
-rw-r--r-- | extension/ChangeLog | 76 | ||||
-rw-r--r-- | extension/rwarray.3am | 35 | ||||
-rw-r--r-- | extension/rwarray.c | 298 | ||||
-rw-r--r-- | extension/testext.c | 77 | ||||
-rw-r--r-- | gawkapi.c | 6 | ||||
-rw-r--r-- | pc/ChangeLog | 4 | ||||
-rw-r--r-- | pc/Makefile.tst | 19 | ||||
-rw-r--r-- | test/ChangeLog | 17 | ||||
-rw-r--r-- | test/Makefile.am | 22 | ||||
-rw-r--r-- | test/Makefile.in | 22 | ||||
-rw-r--r-- | test/readall.ok | 7 | ||||
-rw-r--r-- | test/readall1.awk | 10 | ||||
-rw-r--r-- | test/readall2.awk | 15 | ||||
-rw-r--r-- | test/testext-mpfr.ok | 2 | ||||
-rw-r--r-- | test/testext.ok | 2 |
21 files changed, 718 insertions, 182 deletions
@@ -90,6 +90,14 @@ * re.c (reflags2str): Ditto. * str_array.c (env_array_func): Ditto. +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.c (api_sym_update): Allow undefined Node_var_new variables + to be converted to arrays, otherwise API functions have no way + of creating an array that is referenced in an undefined fashion in + the program. This is somewhat comparable to how the set_argument + API allows an undefined argument variable to be converted to an array. + 2021-12-02 Andrew J. Schorr <aschorr@telemetry-investments.com> * builtin.c (efwrite): Don't use return in call of function diff --git a/doc/ChangeLog b/doc/ChangeLog index 1f535624..53f82d3d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -19,6 +19,11 @@ * texinfo.tex: Updated from GNULIB. +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in: Document new rwarray functions writeall and readall. + * wordlist: Add readall and writeall. + 2021-11-25 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Add missing @item for AWKgo. Thanks to Antonio diff --git a/doc/gawk.info b/doc/gawk.info index f424ef99..cc695b19 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -29140,8 +29140,8 @@ File: gawk.info, Node: Extension Sample Read write array, Next: Extension Samp 17.7.9 Dumping and Restoring an Array ------------------------------------- -The 'rwarray' extension adds two functions, named 'writea()' and -'reada()', as follows: +The 'rwarray' extension adds four functions, named 'writea()', +'reada()', 'writeall()' and 'readall()', as follows: '@load "rwarray"' This is how you load the extension. @@ -29158,6 +29158,20 @@ The 'rwarray' extension adds two functions, named 'writea()' and argument. It clears the array first. Here too, the return value is one on success, or zero upon failure. +'ret = writeall(file)' + This function takes a string argument, which is the name of the + file to which to dump the state of all variables. Calling this + function is completely equivalent to calling 'writea(file, + SYMTAB)'. It returns one on success, or zero upon failure + +'ret = writeall(file)' + This function takes a string argument, which is the name of the + file from which to read the contents of various global variables. + For each variable in the file, the data is loaded unless the + variable already exists. If the variable already exists, the data + for that variable in the file is ignored. It returns one on + success, or zero upon failure. + The array created by 'reada()' is identical to that written by 'writea()' in the sense that the contents are the same. However, due to implementation issues, the array traversal order of the re-created array @@ -29173,6 +29187,13 @@ written as native binary data. Thus, arrays containing only string data can theoretically be dumped on systems with one byte order and restored on systems with a different one, but this has not been tried. + Note that the 'writeall()' and 'readall()' functions provide a +mechanism for maintaining persistent state across repeated invocations +of a program. If, for example, a program calculates some statistics +based on the data in a series of files, it could save state using +'writeall()' after processing N files, and then reload the state using +'readall()' when the N+1st file arrives to update the results. + Here is an example: @load "rwarray" @@ -29180,6 +29201,10 @@ on systems with a different one, but this has not been tried. ret = writea("arraydump.bin", array) ... ret = reada("arraydump.bin", array) + ... + ret = writeall("globalstate.bin") + ... + ret = readall("globalstate.bin") File: gawk.info, Node: Extension Sample Readfile, Next: Extension Sample Time, Prev: Extension Sample Read write array, Up: Extension Samples @@ -38012,6 +38037,8 @@ Index (line 18) * readable data files, checking: File Checking. (line 6) * readable.awk program: File Checking. (line 11) +* readall() extension function: Extension Sample Read write array. + (line 30) * readdir extension: Extension Sample Readdir. (line 9) * readfile() extension function: Extension Sample Readfile. @@ -38725,6 +38752,8 @@ Index * words, usage counts, generating: Word Sorting. (line 6) * writea() extension function: Extension Sample Read write array. (line 12) +* writeall() extension function: Extension Sample Read write array. + (line 24) * xgettext utility: String Extraction. (line 13) * xor: Bitwise Functions. (line 58) * XOR bitwise operation: Bitwise Functions. (line 6) @@ -39259,92 +39288,92 @@ Ref: table-readdir-file-types1175318 Node: Extension Sample Revout1176386 Node: Extension Sample Rev2way1176975 Node: Extension Sample Read write array1177715 -Node: Extension Sample Readfile1179657 -Node: Extension Sample Time1180752 -Node: Extension Sample API Tests1182504 -Node: gawkextlib1182996 -Node: Extension summary1185914 -Node: Extension Exercises1189616 -Node: Language History1190858 -Node: V7/SVR3.11192514 -Node: SVR41194666 -Node: POSIX1196100 -Node: BTL1197481 -Node: POSIX/GNU1198210 -Node: Feature History1203988 -Node: Common Extensions1221163 -Node: Ranges and Locales1222446 -Ref: Ranges and Locales-Footnote-11227062 -Ref: Ranges and Locales-Footnote-21227089 -Ref: Ranges and Locales-Footnote-31227324 -Node: Contributors1227547 -Node: History summary1233544 -Node: Installation1234924 -Node: Gawk Distribution1235868 -Node: Getting1236352 -Node: Extracting1237315 -Node: Distribution contents1238953 -Node: Unix Installation1246014 -Node: Quick Installation1246818 -Node: Compiling with MPFR1249238 -Node: Shell Startup Files1249928 -Node: Additional Configuration Options1251017 -Node: Configuration Philosophy1253332 -Node: Compiling from Git1255728 -Node: Building the Documentation1256283 -Node: Non-Unix Installation1257667 -Node: PC Installation1258127 -Node: PC Binary Installation1258965 -Node: PC Compiling1259838 -Node: PC Using1260955 -Node: Cygwin1264508 -Node: MSYS1265732 -Node: VMS Installation1266334 -Node: VMS Compilation1267053 -Ref: VMS Compilation-Footnote-11268282 -Node: VMS Dynamic Extensions1268340 -Node: VMS Installation Details1270025 -Node: VMS Running1272287 -Node: VMS GNV1276566 -Node: Bugs1277280 -Node: Bug definition1278192 -Node: Bug address1281128 -Node: Usenet1284516 -Node: Performance bugs1285705 -Node: Asking for help1288626 -Node: Maintainers1290593 -Node: Other Versions1291787 -Node: Installation summary1299951 -Node: Notes1301315 -Node: Compatibility Mode1302109 -Node: Additions1302891 -Node: Accessing The Source1303816 -Node: Adding Code1305253 -Node: New Ports1311445 -Node: Derived Files1315820 -Ref: Derived Files-Footnote-11321480 -Ref: Derived Files-Footnote-21321515 -Ref: Derived Files-Footnote-31322113 -Node: Future Extensions1322227 -Node: Implementation Limitations1322885 -Node: Extension Design1324095 -Node: Old Extension Problems1325239 -Ref: Old Extension Problems-Footnote-11326757 -Node: Extension New Mechanism Goals1326814 -Ref: Extension New Mechanism Goals-Footnote-11330178 -Node: Extension Other Design Decisions1330367 -Node: Extension Future Growth1332480 -Node: Notes summary1333086 -Node: Basic Concepts1334244 -Node: Basic High Level1334925 -Ref: figure-general-flow1335207 -Ref: figure-process-flow1335893 -Ref: Basic High Level-Footnote-11339195 -Node: Basic Data Typing1339380 -Node: Glossary1342708 -Node: Copying1374595 -Node: GNU Free Documentation License1412138 -Node: Index1437258 +Node: Extension Sample Readfile1180881 +Node: Extension Sample Time1181976 +Node: Extension Sample API Tests1183728 +Node: gawkextlib1184220 +Node: Extension summary1187138 +Node: Extension Exercises1190840 +Node: Language History1192082 +Node: V7/SVR3.11193738 +Node: SVR41195890 +Node: POSIX1197324 +Node: BTL1198705 +Node: POSIX/GNU1199434 +Node: Feature History1205212 +Node: Common Extensions1222387 +Node: Ranges and Locales1223670 +Ref: Ranges and Locales-Footnote-11228286 +Ref: Ranges and Locales-Footnote-21228313 +Ref: Ranges and Locales-Footnote-31228548 +Node: Contributors1228771 +Node: History summary1234768 +Node: Installation1236148 +Node: Gawk Distribution1237092 +Node: Getting1237576 +Node: Extracting1238539 +Node: Distribution contents1240177 +Node: Unix Installation1247238 +Node: Quick Installation1248042 +Node: Compiling with MPFR1250462 +Node: Shell Startup Files1251152 +Node: Additional Configuration Options1252241 +Node: Configuration Philosophy1254556 +Node: Compiling from Git1256952 +Node: Building the Documentation1257507 +Node: Non-Unix Installation1258891 +Node: PC Installation1259351 +Node: PC Binary Installation1260189 +Node: PC Compiling1261062 +Node: PC Using1262179 +Node: Cygwin1265732 +Node: MSYS1266956 +Node: VMS Installation1267558 +Node: VMS Compilation1268277 +Ref: VMS Compilation-Footnote-11269506 +Node: VMS Dynamic Extensions1269564 +Node: VMS Installation Details1271249 +Node: VMS Running1273511 +Node: VMS GNV1277790 +Node: Bugs1278504 +Node: Bug definition1279416 +Node: Bug address1282352 +Node: Usenet1285740 +Node: Performance bugs1286929 +Node: Asking for help1289850 +Node: Maintainers1291817 +Node: Other Versions1293011 +Node: Installation summary1301175 +Node: Notes1302539 +Node: Compatibility Mode1303333 +Node: Additions1304115 +Node: Accessing The Source1305040 +Node: Adding Code1306477 +Node: New Ports1312669 +Node: Derived Files1317044 +Ref: Derived Files-Footnote-11322704 +Ref: Derived Files-Footnote-21322739 +Ref: Derived Files-Footnote-31323337 +Node: Future Extensions1323451 +Node: Implementation Limitations1324109 +Node: Extension Design1325319 +Node: Old Extension Problems1326463 +Ref: Old Extension Problems-Footnote-11327981 +Node: Extension New Mechanism Goals1328038 +Ref: Extension New Mechanism Goals-Footnote-11331402 +Node: Extension Other Design Decisions1331591 +Node: Extension Future Growth1333704 +Node: Notes summary1334310 +Node: Basic Concepts1335468 +Node: Basic High Level1336149 +Ref: figure-general-flow1336431 +Ref: figure-process-flow1337117 +Ref: Basic High Level-Footnote-11340419 +Node: Basic Data Typing1340604 +Node: Glossary1343932 +Node: Copying1375819 +Node: GNU Free Documentation License1413362 +Node: Index1438482 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 5881a3b8..c319de19 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -39748,8 +39748,9 @@ is: @node Extension Sample Read write array @subsection Dumping and Restoring an Array -The @code{rwarray} extension adds two functions, -named @code{writea()} and @code{reada()}, as follows: +The @code{rwarray} extension adds four functions, +named @code{writea()}, @code{reada()}, +@code{writeall()} and @code{readall()}, as follows: @table @code @item @@load "rwarray" @@ -39768,6 +39769,24 @@ success, or zero upon failure. it reads the file named as its first argument, filling in the array named as the second argument. It clears the array first. Here too, the return value is one on success, or zero upon failure. + +@cindex @code{writeall()} extension function +@item ret = writeall(file) +This function takes a string argument, which is the name of the file +to which to dump the state of all variables. +Calling this function +is completely equivalent to calling +@code{writea(file, SYMTAB)}. +It returns one on success, or zero upon failure + +@cindex @code{readall()} extension function +@item ret = writeall(file) +This function takes a string argument, which is the name of the +file from which to read the contents of various global variables. +For each variable in the file, the data is loaded unless the variable +already exists. If the variable already exists, the data for that variable +in the file is ignored. +It returns one on success, or zero upon failure. @end table The array created by @code{reada()} is identical to that written by @@ -39785,6 +39804,13 @@ as native binary data. Thus, arrays containing only string data can theoretically be dumped on systems with one byte order and restored on systems with a different one, but this has not been tried. +Note that the @code{writeall()} and @code{readall()} functions provide +a mechanism for maintaining persistent state across repeated invocations of a +program. If, for example, a program calculates some statistics based on the +data in a series of files, it could save state using @code{writeall()} after +processing N files, and then reload the state using @code{readall()} when +the N+1st file arrives to update the results. + Here is an example: @example @@ -39793,6 +39819,10 @@ Here is an example: ret = writea("arraydump.bin", array) @dots{} ret = reada("arraydump.bin", array) +@dots{} +ret = writeall("globalstate.bin") +@dots{} +ret = readall("globalstate.bin") @end example @node Extension Sample Readfile diff --git a/doc/gawktexi.in b/doc/gawktexi.in index 8ad59282..134c5558 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -38591,8 +38591,9 @@ is: @node Extension Sample Read write array @subsection Dumping and Restoring an Array -The @code{rwarray} extension adds two functions, -named @code{writea()} and @code{reada()}, as follows: +The @code{rwarray} extension adds four functions, +named @code{writea()}, @code{reada()}, +@code{writeall()} and @code{readall()}, as follows: @table @code @item @@load "rwarray" @@ -38611,6 +38612,24 @@ success, or zero upon failure. it reads the file named as its first argument, filling in the array named as the second argument. It clears the array first. Here too, the return value is one on success, or zero upon failure. + +@cindex @code{writeall()} extension function +@item ret = writeall(file) +This function takes a string argument, which is the name of the file +to which to dump the state of all variables. +Calling this function +is completely equivalent to calling +@code{writea(file, SYMTAB)}. +It returns one on success, or zero upon failure + +@cindex @code{readall()} extension function +@item ret = writeall(file) +This function takes a string argument, which is the name of the +file from which to read the contents of various global variables. +For each variable in the file, the data is loaded unless the variable +already exists. If the variable already exists, the data for that variable +in the file is ignored. +It returns one on success, or zero upon failure. @end table The array created by @code{reada()} is identical to that written by @@ -38628,6 +38647,13 @@ as native binary data. Thus, arrays containing only string data can theoretically be dumped on systems with one byte order and restored on systems with a different one, but this has not been tried. +Note that the @code{writeall()} and @code{readall()} functions provide +a mechanism for maintaining persistent state across repeated invocations of a +program. If, for example, a program calculates some statistics based on the +data in a series of files, it could save state using @code{writeall()} after +processing N files, and then reload the state using @code{readall()} when +the N+1st file arrives to update the results. + Here is an example: @example @@ -38636,6 +38662,10 @@ Here is an example: ret = writea("arraydump.bin", array) @dots{} ret = reada("arraydump.bin", array) +@dots{} +ret = writeall("globalstate.bin") +@dots{} +ret = readall("globalstate.bin") @end example @node Extension Sample Readfile diff --git a/doc/wordlist b/doc/wordlist index 1ad1c429..fd7c181e 100644 --- a/doc/wordlist +++ b/doc/wordlist @@ -1510,6 +1510,7 @@ rapidjson rdev rdquo reada +readall readdir readfile readline @@ -1796,6 +1797,7 @@ wnewmail wordfreq wr writea +writeall www wy xA diff --git a/extension/ChangeLog b/extension/ChangeLog index 52cc493c..bbdf27a0 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -5,10 +5,86 @@ * readfile.c (do_readfile): Close fd if text == NULL. +2021-12-10 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * rwarray.c (write_number): Update comment to reflect that we are + now using mpfr_get_default_rounding_mode() instead of MPFR_RNDN. + 2021-12-10 Arnold D. Robbins <arnold@skeeve.com> * rwarray.c (write_number, read_number): Reformat comments a bit. +2021-12-09 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * rwarray.c (write_number, read_number): Use + mpfr_get_default_rounding_mode() instead of arbitrarily choosing + MPFR_RNDN, taking advantage of the fact that core gawk maintains + this using the ROUNDMODE global variable. + +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * rwarray.c: Fix valgrind complaints related to creating mpz and mpfr + values on the stack in read_number by passing down storage from + the calling function that loads the data into gawk. + (value_storage): New union type to contain mpz_t or mpfr_t data. + (read_global): Allocate value_storage on the stack and pass a pointer + to read_elem. + (read_array): Ditto. + (read_elem): Receive new arg pointing to value_storage, and pass it + down to read_value. + (read_value): Receive new arg pointing to value_storage, and pass it + down to read_number. + (read_number): Receive new arg pointing to value_storage, and create + mpz and mpfr variables using that storage instead of in the local + scope. + +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * rwarray.c: Add new functions writeall and readall to implement + persistent state. + (write_backend): New helper function containing most of the logic + from do_writea. Note that we do not need to check nargs < 2 because + gawk will issue a fatal error if a function is called with fewer + than min_required_args. Clean up some minor issues with error + handling. + (do_writea): Grab the array argument and use write_backend to + do the rest of the work. + (do_writeall): Lookup SYMTAB and invoke write_backend. + (free_value): New function to free memory for data we end up ignoring + because the variables exist already. + (do_poke): Attempt to create variables that don't exist already or + are undefined. + (regular_array_handle): Wrapper around create_array. + (global_array_handle): Call create_array unless the variable exists + already and is an array with zero elements. + (read_global): New function used by readall to load global variables + from a file. + (read_one): New function to read a single array from a file. + (read_backend): New helper function containing most of the logic + from do_reada. Remove the superfluous nargs check. Read the file + prologue and then call read_global or read_one as appropriate to load + the data. + (do_reada): Grab the array argument and call read_backend with + read_one to load the data. + (do_readall): Call read_backend with read_global to load the data. + (read_array): Call read_elem with additional arg regular_array_handle. + (read_elem): Add a function argument controlling array creation to + pass down to read_value. + (read_value): Add a function argument to call for array creation + instead of calling create_array directly, since we may need to use + an existing array when populating global arrays in readall. + (func_table): Add writeall and readall. + * rwarray.3am: Document new functions writeall and readall. + +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * testext.c (test_array_create): New function to create an array + by name that enables testing whether an undefined variable can + be converted by the API into an array. + (populate_array): New helper function. + (fill_in_array): Use populate_array to fill in the elements. + (func_table): Add test_array_create. + 2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> * rwarray.c (write_number): Since mpfr_fpif_export is experimental diff --git a/extension/rwarray.3am b/extension/rwarray.3am index f17ffaa9..b10545a3 100644 --- a/extension/rwarray.3am +++ b/extension/rwarray.3am @@ -1,6 +1,6 @@ .TH RWARRAY 3am "Feb 02 2018" "Free Software Foundation" "GNU Awk Extension Modules" .SH NAME -writea, reada \- write and read gawk arrays to/from files +writea, reada, writeall, readall \- write and read gawk arrays to/from files .SH SYNOPSIS .ft CW @load "rwarray" @@ -8,14 +8,20 @@ writea, reada \- write and read gawk arrays to/from files ret = writea(file, array) .br ret = reada(file, array) +.br +ret = writeall(file) +.br +ret = readall(file) .ft R .SH DESCRIPTION The .I rwarray -extension adds two functions named -.BR writea() . -and +extension adds functions named +.BR writea() , .BR reada() , +.BR writeaall() , +and +.BR readaall() , as follows. .TP .B writea() @@ -33,6 +39,23 @@ it reads the file named as its first argument, filling in the array named as the second argument. It clears the array first. Here too, the return value is one on success and zero upon failure. +.TP +.B writeall() +This function takes a string argument, which is the name of the +file to which dump the state of all variables. Calling this function +is completely equivalent to calling +.B writea() +with the second argument equal to +.BR SYMTAB . +It returns one on success, or zero upon failure. +.TP +.B readall() +This function takes a string argument, which is the name of the +file from which to read the contents of various global variables. +For each variable in the file, the data is loaded unless the variable +already exists. If the variable already exists, the data for that variable +in the file is ignored. +It returns one on success, or zero upon failure. .SH NOTES The array created by .B reada() @@ -62,6 +85,10 @@ restored on systems with a different one, but this has not been tried. ret = writea("arraydump.bin", array) \&... ret = reada("arraydump.bin", array) +\&... +ret = writeall("globalstate.bin") +\&... +ret = readall("globalstate.bin") .fi .ft R .SH "SEE ALSO" diff --git a/extension/rwarray.c b/extension/rwarray.c index 532a8da1..54032e5e 100644 --- a/extension/rwarray.c +++ b/extension/rwarray.c @@ -78,10 +78,16 @@ static awk_bool_t write_elem(FILE *fp, awk_element_t *element); static awk_bool_t write_value(FILE *fp, awk_value_t *val); static awk_bool_t write_number(FILE *fp, awk_value_t *val); +typedef union { + mpz_t mpz_val; + mpfr_t mpfr_val; +} value_storage; + +typedef awk_array_t (*array_handle_t)(awk_value_t *); static awk_bool_t read_array(FILE *fp, awk_array_t array); -static awk_bool_t read_elem(FILE *fp, awk_element_t *element); -static awk_bool_t read_value(FILE *fp, awk_value_t *value); -static awk_bool_t read_number(FILE *fp, awk_value_t *value, uint32_t code); +static awk_bool_t read_elem(FILE *fp, awk_element_t *element, array_handle_t, value_storage *); +static awk_bool_t read_value(FILE *fp, awk_value_t *value, array_handle_t, awk_value_t *idx, value_storage *vs); +static awk_bool_t read_number(FILE *fp, awk_value_t *value, uint32_t code, value_storage *); /* * Format of array info: @@ -117,12 +123,12 @@ static awk_bool_t read_number(FILE *fp, awk_value_t *value, uint32_t code); #define VT_BOOL 8 #define VT_UNDEFINED 20 -/* do_writea --- write an array */ +/* write_backend --- write an array */ static awk_value_t * -do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) +write_backend(awk_value_t *result, awk_array_t array, const char *name) { - awk_value_t filename, array; + awk_value_t filename; FILE *fp = NULL; uint32_t major = MAJOR; uint32_t minor = MINOR; @@ -130,18 +136,9 @@ do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) assert(result != NULL); make_number(0.0, result); - if (nargs < 2) - goto out; - - /* filename is first arg, array to dump is second */ + /* filename is first arg */ if (! get_argument(0, AWK_STRING, & filename)) { - warning(ext_id, _("do_writea: first argument is not a string")); - errno = EINVAL; - goto done1; - } - - if (! get_argument(1, AWK_ARRAY, & array)) { - warning(ext_id, _("do_writea: second argument is not an array")); + warning(ext_id, _("%s: first argument is not a string"), name); errno = EINVAL; goto done1; } @@ -162,21 +159,55 @@ do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) if (fwrite(& minor, 1, sizeof(minor), fp) != sizeof(minor)) goto done1; - if (write_array(fp, array.array_cookie)) { + if (write_array(fp, array)) { make_number(1.0, result); - goto done0; + fclose(fp); + return result; } done1: update_ERRNO_int(errno); - unlink(filename.str_value.str); - -done0: - fclose(fp); -out: + if (fp != NULL) { + fclose(fp); + unlink(filename.str_value.str); + } return result; } +/* do_writea --- write an array */ + +static awk_value_t * +do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + awk_value_t array; + + if (! get_argument(1, AWK_ARRAY, & array)) { + warning(ext_id, _("writea: second argument is not an array")); + errno = EINVAL; + update_ERRNO_int(errno); + make_number(0.0, result); + return result; + } + return write_backend(result, array.array_cookie, "writea"); +} + +/* do_writeall --- write out SYMTAB */ + +static awk_value_t * +do_writeall(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + awk_value_t array; + + if (! sym_lookup("SYMTAB", AWK_ARRAY, & array)) { + warning(ext_id, _("writeall: unable to find SYMTAB array")); + errno = EINVAL; + update_ERRNO_int(errno); + make_number(0.0, result); + return result; + } + return write_backend(result, array.array_cookie, "writeall"); +} + /* write_array --- write out an array or a sub-array */ @@ -340,9 +371,9 @@ write_number(FILE *fp, awk_value_t *val) if (mpfr_fpif_export(fp, val->num_ptr) != 0) #else #define MPFR_STR_BASE 62 /* maximize base to minimize string len */ -#define MPFR_STR_ROUND MPFR_RNDN +#define MPFR_STR_ROUND mpfr_get_default_rounding_mode() /* - * XXX does the choice of MPFR_RNDN matter, given + * Does the choice of rounding mode matter, given * that the precision is 0, so we should be rendering * in full precision? */ @@ -367,12 +398,139 @@ write_number(FILE *fp, awk_value_t *val) return awk_true; } -/* do_reada --- read an array */ +/* free_value --- release memory for ignored global variables */ + +static void +free_value(awk_value_t *v) +{ + switch (v->val_type) { + case AWK_ARRAY: + clear_array(v->array_cookie); + break; + case AWK_STRING: + case AWK_REGEX: + case AWK_STRNUM: + case AWK_UNDEFINED: + gawk_free(v->str_value.str); + break; + case AWK_BOOL: + /* no memory allocated */ + break; + case AWK_NUMBER: + switch (v->num_type) { + case AWK_NUMBER_TYPE_DOUBLE: + /* no memory allocated */ + break; + case AWK_NUMBER_TYPE_MPZ: + mpz_clear(v->num_ptr); + break; + case AWK_NUMBER_TYPE_MPFR: + mpfr_clear(v->num_ptr); + break; + default: + warning(ext_id, _("cannot free number with unknown type %d"), v->num_type); + break; + } + break; + default: + warning(ext_id, _("cannot free value with unhandled type %d"), v->val_type); + break; + } +} + +/* do_poke --- create a global variable */ + +static awk_bool_t +do_poke(awk_element_t *e) +{ + awk_value_t t; + + if (e->index.val_type != AWK_STRING) + return awk_false; + /* So this is a bit tricky. If the program refers to the variable, + * then it will already exist in an undefined state after parsing. + * If the program never refers to it, then the lookup fails. + * We still need to create it in case the program accesses it via + * indirection through the SYMTAB table. */ + if (sym_lookup(e->index.str_value.str, AWK_UNDEFINED, &t) && (t.val_type != AWK_UNDEFINED)) + return awk_false; + if (! sym_update(e->index.str_value.str, & e->value)) { + warning(ext_id, _("readall: unable to set %s"), e->index.str_value.str); + return awk_false; + } + return awk_true; +} + +/* regular_array_handle --- array creation hook for normal reada */ + +static awk_array_t +regular_array_handle(awk_value_t *unused) +{ + return create_array(); +} + +/* global_array_handle --- array creation hook for readall */ + +static awk_array_t +global_array_handle(awk_value_t *n) +{ + awk_value_t t; + size_t count; + + /* The array may exist already because it was instantiated during + * program parsing, so we use the existing array if it is empty. */ + return ((n->val_type == AWK_STRING) && sym_lookup(n->str_value.str, AWK_UNDEFINED, &t) && (t.val_type == AWK_ARRAY) && get_element_count(t.array_cookie, & count) && ! count) ? t.array_cookie : create_array(); +} + +/* read_global --- read top-level variables dumped from SYMTAB */ + +static awk_bool_t +read_global(FILE *fp, awk_array_t unused) +{ + uint32_t i; + uint32_t count; + awk_element_t new_elem; + value_storage vs; + + if (fread(& count, 1, sizeof(count), fp) != sizeof(count)) + return awk_false; + + count = ntohl(count); + + for (i = 0; i < count; i++) { + if (read_elem(fp, & new_elem, global_array_handle, &vs)) { + if (! do_poke(& new_elem)) + free_value(& new_elem.value); + if (new_elem.index.str_value.len) + /* free string allocated by make_const_string */ + gawk_free(new_elem.index.str_value.str); + } else + return awk_false; + } + + return awk_true; +} + +/* read_one --- read one array */ + +static awk_bool_t +read_one(FILE *fp, awk_array_t array) +{ + if (! clear_array(array)) { + errno = ENOMEM; + warning(ext_id, _("reada: clear_array failed")); + return awk_false; + } + + return read_array(fp, array); +} + +/* read_backend --- common code for reada and readall */ static awk_value_t * -do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) +read_backend(awk_value_t *result, awk_array_t array, const char *name, awk_bool_t (*func)(FILE *, awk_array_t)) { - awk_value_t filename, array; + awk_value_t filename; FILE *fp = NULL; uint32_t major; uint32_t minor; @@ -381,18 +539,9 @@ do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) assert(result != NULL); make_number(0.0, result); - if (nargs < 2) - goto out; - - /* directory is first arg, array to read is second */ + /* filename is first arg */ if (! get_argument(0, AWK_STRING, & filename)) { - warning(ext_id, _("do_reada: first argument is not a string")); - errno = EINVAL; - goto done1; - } - - if (! get_argument(1, AWK_ARRAY, & array)) { - warning(ext_id, _("do_reada: second argument is not an array")); + warning(ext_id, _("%s: first argument is not a string"), name); errno = EINVAL; goto done1; } @@ -434,13 +583,7 @@ do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) goto done1; } - if (! clear_array(array.array_cookie)) { - errno = ENOMEM; - warning(ext_id, _("do_reada: clear_array failed")); - goto done1; - } - - if (read_array(fp, array.array_cookie)) { + if ((*func)(fp, array)) { make_number(1.0, result); goto done0; } @@ -450,10 +593,34 @@ done1: done0: if (fp != NULL) fclose(fp); -out: return result; } +/* do_reada --- read an array */ + +static awk_value_t * +do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + awk_value_t array; + + if (! get_argument(1, AWK_ARRAY, & array)) { + warning(ext_id, _("reada: second argument is not an array")); + errno = EINVAL; + update_ERRNO_int(errno); + make_number(0.0, result); + return result; + } + return read_backend(result, array.array_cookie, "read", read_one); +} + +/* do_readall --- read top-level variables */ + +static awk_value_t * +do_readall(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + return read_backend(result, NULL, "readall", read_global); +} + /* read_array --- read in an array or sub-array */ @@ -463,6 +630,7 @@ read_array(FILE *fp, awk_array_t array) uint32_t i; uint32_t count; awk_element_t new_elem; + value_storage vs; if (fread(& count, 1, sizeof(count), fp) != sizeof(count)) return awk_false; @@ -470,7 +638,7 @@ read_array(FILE *fp, awk_array_t array) count = ntohl(count); for (i = 0; i < count; i++) { - if (read_elem(fp, & new_elem)) { + if (read_elem(fp, & new_elem, regular_array_handle, &vs)) { /* add to array */ if (! set_array_element_by_elem(array, & new_elem)) { warning(ext_id, _("read_array: set_array_element failed")); @@ -489,7 +657,7 @@ read_array(FILE *fp, awk_array_t array) /* read_elem --- read in a single element */ static awk_bool_t -read_elem(FILE *fp, awk_element_t *element) +read_elem(FILE *fp, awk_element_t *element, array_handle_t array_handle, value_storage *vs) { uint32_t index_len; static char *buffer; @@ -527,7 +695,7 @@ read_elem(FILE *fp, awk_element_t *element) make_null_string(& element->index); } - if (! read_value(fp, & element->value)) + if (! read_value(fp, & element->value, array_handle, & element->index, vs)) return awk_false; return awk_true; @@ -536,7 +704,7 @@ read_elem(FILE *fp, awk_element_t *element) /* read_value --- read a number or a string */ static awk_bool_t -read_value(FILE *fp, awk_value_t *value) +read_value(FILE *fp, awk_value_t *value, array_handle_t array_handle, awk_value_t *idx, value_storage *vs) { uint32_t code, len; @@ -546,7 +714,7 @@ read_value(FILE *fp, awk_value_t *value) code = ntohl(code); if (code == VT_ARRAY) { - awk_array_t array = create_array(); + awk_array_t array = (*array_handle)(idx); if (! read_array(fp, array)) return awk_false; @@ -557,7 +725,7 @@ read_value(FILE *fp, awk_value_t *value) } else if (code == VT_NUMBER || code == VT_GMP || code == VT_MPFR) { - return read_number(fp, value, code); + return read_number(fp, value, code, vs); } else { if (fread(& len, 1, sizeof(len), fp) != sizeof(len)) { return awk_false; @@ -610,7 +778,7 @@ read_value(FILE *fp, awk_value_t *value) /* read_number --- read a double, GMP, or MPFR number */ static awk_bool_t -read_number(FILE *fp, awk_value_t *value, uint32_t code) +read_number(FILE *fp, awk_value_t *value, uint32_t code, value_storage *vs) { uint32_t len; @@ -632,28 +800,24 @@ read_number(FILE *fp, awk_value_t *value, uint32_t code) } else { #ifdef HAVE_MPFR if (code == VT_GMP) { - mpz_t mp_ptr; - - mpz_init(mp_ptr); - if (mpz_inp_raw(mp_ptr, fp) == 0) + mpz_init(vs->mpz_val); + if (mpz_inp_raw(vs->mpz_val, fp) == 0) return awk_false; - value = make_number_mpz(mp_ptr, value); + value = make_number_mpz(vs->mpz_val, value); } else { - mpfr_t mpfr_val; - mpfr_init(mpfr_val); - + mpfr_init(vs->mpfr_val); #ifdef USE_MPFR_FPIF /* preferable if widely available and stable */ - if (mpfr_fpif_import(mpfr_val, fp) != 0) + if (mpfr_fpif_import(vs->mpfr_val, fp) != 0) #else // N.B. need to consume the terminating space we wrote // after mpfr_out_str - if ((mpfr_inp_str(mpfr_val, fp, MPFR_STR_BASE, MPFR_STR_ROUND) == 0) || (getc(fp) != ' ')) + if ((mpfr_inp_str(vs->mpfr_val, fp, MPFR_STR_BASE, MPFR_STR_ROUND) == 0) || (getc(fp) != ' ')) #endif return awk_false; - value = make_number_mpfr(& mpfr_val, value); + value = make_number_mpfr(vs->mpfr_val, value); } #else fatal(ext_id(_("rwarray extension: GMP/MPFR value in file but compiled without GMP/MPFR support.")); @@ -666,6 +830,8 @@ read_number(FILE *fp, awk_value_t *value, uint32_t code) static awk_ext_func_t func_table[] = { { "writea", do_writea, 2, 2, awk_false, NULL }, { "reada", do_reada, 2, 2, awk_false, NULL }, + { "writeall", do_writeall, 1, 1, awk_false, NULL }, + { "readall", do_readall, 1, 1, awk_false, NULL }, }; diff --git a/extension/testext.c b/extension/testext.c index bfaa8637..18465f2a 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -48,6 +48,7 @@ static const char *ext_version = "testext extension: version 1.0"; int plugin_is_GPL_compatible; static void fill_in_array(awk_value_t *value); +static int populate_array(awk_array_t); #ifdef __MINGW32__ unsigned int @@ -666,6 +667,54 @@ out: } /* +function tfunc(f) { + if (isarray(f)) + print "good: we have an array" +} + +BEGIN { + printf "test_array_create returned %d\n", test_array_create("testarr") + tfunc(testarr) +} +*/ + +static awk_value_t * +test_array_create(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + awk_value_t new_array; + awk_value_t arg0; + + (void) nargs; /* silence warnings */ + make_number(0.0, result); + + if (! get_argument(0, AWK_STRING, & arg0)) { + printf("test_array_create: could not get argument\n"); + goto out; + } + + if (arg0.val_type != AWK_STRING) { + printf("test_array_create: argument is not string (%d)\n", + arg0.val_type); + goto out; + } + + new_array.val_type = AWK_ARRAY; + new_array.array_cookie = create_array(); + if (! sym_update(arg0.str_value.str, & new_array)) { + printf("test_array_create: sym_update(\"%s\") failed!\n", arg0.str_value.str); + goto out; + } + if (populate_array(new_array.array_cookie) < 0) { + printf("test_array_create: populate(\"%s\") failed!\n", arg0.str_value.str); + goto out; + } + + make_number(1.0, result); +out: + return result; +} + +/* BEGIN { printf("Initial value of LINT is %d\n", LINT) ret = print_do_lint(); @@ -958,29 +1007,40 @@ do_get_file(int nargs, awk_value_t *result, struct awk_ext_func *unused) return make_number(1.0, result); } -/* fill_in_array --- fill in a new array */ +/* populate_array --- fill in some array values */ -static void -fill_in_array(awk_value_t *new_array) +static int +populate_array(awk_array_t a_cookie) { - awk_array_t a_cookie; awk_value_t index, value; - a_cookie = create_array(); - (void) make_const_string("hello", 5, & index); (void) make_const_string("world", 5, & value); if (! set_array_element(a_cookie, & index, & value)) { printf("fill_in_array:%d: set_array_element failed\n", __LINE__); - return; + return -1; } (void) make_const_string("answer", 6, & index); (void) make_number(42.0, & value); if (! set_array_element(a_cookie, & index, & value)) { printf("fill_in_array:%d: set_array_element failed\n", __LINE__); - return; + return -1; } + return 0; +} + +/* fill_in_array --- fill in a new array */ + +static void +fill_in_array(awk_value_t *new_array) +{ + awk_array_t a_cookie; + + a_cookie = create_array(); + + if (populate_array(a_cookie) < 0) + return; new_array->val_type = AWK_ARRAY; new_array->array_cookie = a_cookie; @@ -1061,6 +1121,7 @@ static awk_ext_func_t func_table[] = { { "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 }, + { "test_array_create", test_array_create, 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 }, @@ -881,7 +881,8 @@ api_sym_update(awk_ext_id_t id, /* * If we get here, then it exists already. Any valid type is - * OK except for AWK_ARRAY. + * OK except for AWK_ARRAY (unless it is in Node_var_new undefined + * state, in which case an array is OK). */ if ( (node->flags & NO_EXT_SET) != 0 || is_off_limits_var(full_name)) { /* most built-in vars not allowed */ @@ -892,8 +893,7 @@ api_sym_update(awk_ext_id_t id, efree((void *) full_name); - if ( value->val_type != AWK_ARRAY - && (node->type == Node_var || node->type == Node_var_new)) { + if ((node->type == Node_var && value->val_type != AWK_ARRAY) || node->type == Node_var_new) { unref(node->var_value); node->var_value = awk_value_to_node(value); if (node->type == Node_var_new && value->val_type != AWK_UNDEFINED) diff --git a/pc/ChangeLog b/pc/ChangeLog index cc48e0c2..342ae067 100644 --- a/pc/ChangeLog +++ b/pc/ChangeLog @@ -10,6 +10,10 @@ * Makefile.tst: Regenerated. +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.tst: Regenerated. + 2021-12-01 Arnold D. Robbins <arnold@skeeve.com> * gawkmisc.pc (os_maybe_set_errno): Renamed from diff --git a/pc/Makefile.tst b/pc/Makefile.tst index f49d66bd..d74172d1 100644 --- a/pc/Makefile.tst +++ b/pc/Makefile.tst @@ -235,6 +235,7 @@ SHLIB_TESTS = \ getfile \ inplace1 inplace2 inplace2bcomp inplace3 inplace3bcomp \ ordchr ordchr2 \ + readall \ readdir readdir_test readdir_retest readfile readfile2 revout \ revtwoway rwarray \ testext time @@ -347,7 +348,8 @@ EXPECTED_FAIL_ZOS = \ GENTESTS_UNUSED = Makefile.in checknegtime.awk dtdgport.awk fix-fmtspcl.awk \ fmtspcl-mpfr.ok fmtspcl.awk fmtspcl.tok gtlnbufv.awk hello.awk \ inchello.awk inclib.awk inplace.1.in inplace.2.in inplace.in \ - printfloat.awk readdir0.awk valgrind.awk xref.awk + printfloat.awk readdir0.awk valgrind.awk xref.awk \ + readall1.awk readall2.awk # List of tests on MinGW or DJGPP that need a different cmp program @@ -1027,7 +1029,7 @@ inplace3bcomp:: testext:: @echo $@ - @-$(AWK) ' /^(@load|BEGIN)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk + @-$(AWK) ' /^(@load|BEGIN|function)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk @-$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null; \ then $(CMP) "$(srcdir)"/$@-mpfr.ok _$@ && rm -f _$@ testext.awk testexttmp.txt ; \ @@ -1065,6 +1067,13 @@ readdir_retest: @-$(AWK) -lreaddir_test -F$(SLASH) -f "$(srcdir)"/$@.awk "$(top_srcdir)" > _$@ @-$(CMP) $@.ok _$@ && rm -f $@.ok _$@ +readall: + @echo $@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@1.awk -v "ofile=readall.state" > _$@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@2.awk -v "ifile=readall.state" >> _$@ + @-$(CMP) $@.ok _$@ && rm -f _$@ + @-$(RM) -f readall.state + fts: @echo $@ @echo Expect $@ to fail with MinGW. @@ -3697,7 +3706,11 @@ diffout: if [ "$$i" != "_*" ]; then \ echo ============== $$i ============= ; \ base=`echo $$i | sed 's/^_//'` ; \ - if [ -r $${base}.ok ]; then \ + if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r $${base}-mpfr.ok ]; then \ + diff -u $${base}-mpfr.ok $$i ; \ + elif echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r "$(srcdir)"/$${base}-mpfr.ok ]; then \ + diff -u "$(srcdir)"/$${base}-mpfr.ok $$i ; \ + elif [ -r $${base}.ok ]; then \ diff -u $${base}.ok $$i ; \ else \ diff -u "$(srcdir)"/$${base}.ok $$i ; \ diff --git a/test/ChangeLog b/test/ChangeLog index 6d1758b5..9b8567d1 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -17,6 +17,23 @@ * Makefile.am (EXTRA_DIST): nsidentifier, new test. * nsidentifier.awk, nsidentifier.ok: New files. +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): Add readall1.awk, readall2.awk, and + readall.ok. + (SHLIB_TESTS): Add readall. + (GENTESTS_UNUSED): Add readall1.awk and readall2.awk. + (readall): Add new test of the writeall and readall functions. + * readall1.awk, readall2.awk, readall.ok: New files. + +2021-12-08 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (testext): Change awk pattern to include functions in + testext.awk. + (diffout): If running MPFR tests and there's an mpfr.ok file, compare + to that instead of to the regular ok file. + * testext.ok, testext-mpfr.ok: Update for new test_array_create test. + 2021-12-07 Andrew J. Schorr <aschorr@telemetry-investments.com> * iolint.awk, iolint.ok: Reorder "cat" pipe/output file test to reduce diff --git a/test/Makefile.am b/test/Makefile.am index 1a22118b..ddca3f59 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1037,6 +1037,9 @@ EXTRA_DIST = \ range1.ok \ range2.awk \ range2.ok \ + readall1.awk \ + readall2.awk \ + readall.ok \ readbuf.awk \ readbuf.ok \ readdir.awk \ @@ -1498,6 +1501,7 @@ SHLIB_TESTS = \ getfile \ inplace1 inplace2 inplace2bcomp inplace3 inplace3bcomp \ ordchr ordchr2 \ + readall \ readdir readdir_test readdir_retest readfile readfile2 revout \ revtwoway rwarray \ testext time @@ -1605,7 +1609,8 @@ ZOS_FAIL = @ZOS_FAIL@ GENTESTS_UNUSED = Makefile.in checknegtime.awk dtdgport.awk fix-fmtspcl.awk \ fmtspcl-mpfr.ok fmtspcl.awk fmtspcl.tok gtlnbufv.awk hello.awk \ inchello.awk inclib.awk inplace.1.in inplace.2.in inplace.in \ - printfloat.awk readdir0.awk valgrind.awk xref.awk + printfloat.awk readdir0.awk valgrind.awk xref.awk \ + readall1.awk readall2.awk # List of tests on MinGW or DJGPP that need a different cmp program NEED_TESTOUTCMP = \ @@ -2289,7 +2294,7 @@ inplace3bcomp:: testext:: @echo $@ - @-$(AWK) ' /^(@load|BEGIN)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk + @-$(AWK) ' /^(@load|BEGIN|function)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk @-$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null; \ then $(CMP) "$(srcdir)"/$@-mpfr.ok _$@ && rm -f _$@ testext.awk testexttmp.txt ; \ @@ -2325,6 +2330,13 @@ readdir_retest: @-$(AWK) -lreaddir_test -F/ -f "$(srcdir)"/$@.awk "$(top_srcdir)" > _$@ @-$(CMP) $@.ok _$@ && rm -f $@.ok _$@ +readall: + @echo $@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@1.awk -v "ofile=readall.state" > _$@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@2.awk -v "ifile=readall.state" >> _$@ + @-$(CMP) $@.ok _$@ && rm -f _$@ + @-$(RM) -f readall.state + fts: @echo $@ @-case `uname` in \ @@ -2533,7 +2545,11 @@ diffout: if [ "$$i" != "_*" ]; then \ echo ============== $$i ============= ; \ base=`echo $$i | sed 's/^_//'` ; \ - if [ -r $${base}.ok ]; then \ + if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r $${base}-mpfr.ok ]; then \ + diff -u $${base}-mpfr.ok $$i ; \ + elif echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r "$(srcdir)"/$${base}-mpfr.ok ]; then \ + diff -u "$(srcdir)"/$${base}-mpfr.ok $$i ; \ + elif [ -r $${base}.ok ]; then \ diff -u $${base}.ok $$i ; \ else \ diff -u "$(srcdir)"/$${base}.ok $$i ; \ diff --git a/test/Makefile.in b/test/Makefile.in index be8e0345..d974a98c 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -1303,6 +1303,9 @@ EXTRA_DIST = \ range1.ok \ range2.awk \ range2.ok \ + readall1.awk \ + readall2.awk \ + readall.ok \ readbuf.awk \ readbuf.ok \ readdir.awk \ @@ -1760,6 +1763,7 @@ SHLIB_TESTS = \ getfile \ inplace1 inplace2 inplace2bcomp inplace3 inplace3bcomp \ ordchr ordchr2 \ + readall \ readdir readdir_test readdir_retest readfile readfile2 revout \ revtwoway rwarray \ testext time @@ -1872,7 +1876,8 @@ EXPECTED_FAIL_ZOS = \ GENTESTS_UNUSED = Makefile.in checknegtime.awk dtdgport.awk fix-fmtspcl.awk \ fmtspcl-mpfr.ok fmtspcl.awk fmtspcl.tok gtlnbufv.awk hello.awk \ inchello.awk inclib.awk inplace.1.in inplace.2.in inplace.in \ - printfloat.awk readdir0.awk valgrind.awk xref.awk + printfloat.awk readdir0.awk valgrind.awk xref.awk \ + readall1.awk readall2.awk # List of tests on MinGW or DJGPP that need a different cmp program @@ -2743,7 +2748,7 @@ inplace3bcomp:: testext:: @echo $@ - @-$(AWK) ' /^(@load|BEGIN)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk + @-$(AWK) ' /^(@load|BEGIN|function)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk @-$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null; \ then $(CMP) "$(srcdir)"/$@-mpfr.ok _$@ && rm -f _$@ testext.awk testexttmp.txt ; \ @@ -2779,6 +2784,13 @@ readdir_retest: @-$(AWK) -lreaddir_test -F/ -f "$(srcdir)"/$@.awk "$(top_srcdir)" > _$@ @-$(CMP) $@.ok _$@ && rm -f $@.ok _$@ +readall: + @echo $@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@1.awk -v "ofile=readall.state" > _$@ + @-$(AWK) -lrwarray -f "$(srcdir)"/$@2.awk -v "ifile=readall.state" >> _$@ + @-$(CMP) $@.ok _$@ && rm -f _$@ + @-$(RM) -f readall.state + fts: @echo $@ @-case `uname` in \ @@ -5370,7 +5382,11 @@ diffout: if [ "$$i" != "_*" ]; then \ echo ============== $$i ============= ; \ base=`echo $$i | sed 's/^_//'` ; \ - if [ -r $${base}.ok ]; then \ + if echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r $${base}-mpfr.ok ]; then \ + diff -u $${base}-mpfr.ok $$i ; \ + elif echo "$$GAWK_TEST_ARGS" | egrep -e '-M|--bignum' > /dev/null && [ -r "$(srcdir)"/$${base}-mpfr.ok ]; then \ + diff -u "$(srcdir)"/$${base}-mpfr.ok $$i ; \ + elif [ -r $${base}.ok ]; then \ diff -u $${base}.ok $$i ; \ else \ diff -u "$(srcdir)"/$${base}.ok $$i ; \ diff --git a/test/readall.ok b/test/readall.ok new file mode 100644 index 00000000..b343af59 --- /dev/null +++ b/test/readall.ok @@ -0,0 +1,7 @@ +1 +1 +5.9 3 -2.327 +zebra[archie] = banana +zebra[0] = apple +zebra[3][foo] = bar +zebra[3][bar] = foo diff --git a/test/readall1.awk b/test/readall1.awk new file mode 100644 index 00000000..2888d157 --- /dev/null +++ b/test/readall1.awk @@ -0,0 +1,10 @@ +BEGIN { + x = 5.9 + y = 3 + z = -2.327 + zebra[0] = "apple" + zebra["archie"] = "banana" + zebra[3]["foo"] = "bar" + zebra[3]["bar"] = "foo" + print writeall(ofile) +} diff --git a/test/readall2.awk b/test/readall2.awk new file mode 100644 index 00000000..8b79849a --- /dev/null +++ b/test/readall2.awk @@ -0,0 +1,15 @@ +function printarray(n, x, i) { + for (i in x) { + if (isarray(x[i])) + printarray((n "[" i "]"), x[i]) + else + printf "%s[%s] = %s\n", n, i, x[i] + } +} + +BEGIN { + print readall(ifile) + print x, y, z + #print zebra[0], zebra[3]["foo"], zebra[3]["bar"] + printarray("zebra", zebra) +} diff --git a/test/testext-mpfr.ok b/test/testext-mpfr.ok index 2c616c67..ec584216 100644 --- a/test/testext-mpfr.ok +++ b/test/testext-mpfr.ok @@ -48,6 +48,8 @@ test_array_param: argument is not undefined (1) test_array_param() returned 0 isarray(a_scalar) = 0 +test_array_create returned 1 +good: we have an array Initial value of LINT is 0 print_do_lint: lint = 0 print_do_lint() returned 1 diff --git a/test/testext.ok b/test/testext.ok index fbc3c263..1d058302 100644 --- a/test/testext.ok +++ b/test/testext.ok @@ -48,6 +48,8 @@ test_array_param: argument is not undefined (1) test_array_param() returned 0 isarray(a_scalar) = 0 +test_array_create returned 1 +good: we have an array Initial value of LINT is 0 print_do_lint: lint = 0 print_do_lint() returned 1 |