diff options
88 files changed, 16858 insertions, 12491 deletions
@@ -1,3 +1,162 @@ +2014-11-03 Norihiro Tanaka <noritnk@kcn.ne.jp> + + * re.c (research): Use dfa superset to improve matching speed. + +2014-11-02 Arnold D. Robbins <arnold@skeeve.com> + + * profile.c (div_on_left_mul_on_right): New function. + (parenthesize): Call it. + +2014-10-30 Arnold D. Robbins <arnold@skeeve.com> + + * configure: Regenerated after fix to m4/readline.m4. + + Unrelated; fixes to profiling. Thanks to Hermann Peifer and + Manuel Collado for pointing out problems: + + * profile.c (pprint): For Op_unary_minus, parenthesize -(-x) + correctly. + (prec_level): Get the levels right (checked the grammar). + (is_unary_minus): New function. + (pp_concat): Add checks for unary minus; needs to be parenthesized. + +2014-10-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * NEWS: Mention installation of /etc/profile.d/gawk.{csh,sh}. + +2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * configure.ac (AC_CONFIG_FILES): Add extras/Makefile. + * Makefile.am (SUBDIRS): Add extras. + * extras: Add new subdirectory. + +2014-10-29 Arnold D. Robbins <arnold@skeeve.com> + + * dfa.c: Sync with GNU grep. Again, again. + +2014-10-28 Arnold D. Robbins <arnold@skeeve.com> + + * dfa.c: Sync with GNU grep. Again. + +2014-10-25 Arnold D. Robbins <arnold@skeeve.com> + + * dfa.c: Sync with GNU grep. + +2014-10-17 John E. Malmberg <wb8tyw@qsl.net> + + * ext.c (close_extensions): Test for null pointer since + since this can be called by signal handler before the + pointers are initialized. + +2014-10-15 Arnold D. Robbins <arnold@skeeve.com> + + Make sane the handling of AWKPATH and AWKLIBPATH: + + 1. Don't explicitly search "."; it must be in the path either + physically or as null element a la the shell's $PATH + 2. If environment's value was empty, use built-in default value. + 3. Set ENVIRON["AWK*PATH"] to the path used. + + * io.c (path_info): Remove try_cwd member. + (get_cwd): Removed, not needed anymore. + (do_find_source): Don't do explicit check in current directory. + It must come from the AWKPATH or AWKLIBPATH variable. + * main.c (path_environ): If value from environment was empty, + set it to the default. This is how gawk has behaved since 2.10. + +2014-10-13 Arnold D. Robbins <arnold@skeeve.com> + + * regcomp.c (__re_error_msgid): Make error message for REG_EBRACK + more helpful - also used for unmatched [:, [., [=. + Thanks to Davide Brini for raising the issue. + +2014-10-12 Arnold D. Robbins <arnold@skeeve.com> + + * README: Remove Pat Rankin from VMS duties, per his request. + +2014-10-08 Arnold D. Robbins <arnold@skeeve.com> + + * dfa.c: Sync with GNU grep. + +2014-10-05 Arnold D. Robbins <arnold@skeeve.com> + + * profile.c (pprint): Fix typo in header. Sheesh. + + Unrelated: + + * awkgram.y (mk_program): Add a comment that we don't need to + clear the comment* variables. + +2014-10-04 Arnold D. Robbins <arnold@skeeve.com> + + * profile.c (pp_string_fp): Fix breaklines case to actually + output the current letter. This broke at gawk 4.0.0. Sigh. + Thanks to Bert Bos (bert@w3.org) for the report. + +2014-10-03 Stephen Davies <sdavies@sdc.com.au> + + * awkgram.y (program_comment): Renamed from comment0. + (function_comment): Renamed from commentf. + +2014-10-02 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y, profile.c: Minor white space cleanups. + +2014-10-01 Arnold D. Robbins <arnold@skeeve.com> + + Fix a few compile warnings: + + * awkgram.y (split_comment): Make static. + General: Remove some unused variables, clean up some whitepace nits. + + * profile.c (indent): Add some braces to turn off compiler warnings. + +2014-09-29 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * main.c (main): In optlist, it should say "h", not "h:", since there + is no argument for the help option. Thanks to Joep van Delft for + the bug report. + +2014-09-29 Arnold D. Robbins <arnold@skeeve.com> + + * gawkapi.h: Minor edits to sync with documentation. Does not + influence the behavior of the API. + +2014-09-28 Arnold D. Robbins <arnold@skeeve.com> + + * command.y (cmdtab): Add "where" as an alias for "backtrace". + Finally! + + Unrelated: + + * dfa.c: Sync with GNU grep. + +2014-09-27 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (check_for_bad): Bitwise-and the bad character with 0xFF + to avoid sign extension into a large integer. + + Unrelated: + + * configure.ac: Add an option to enable locale letters in identifiers. + Undocumented and subject to being rescinded at any time in the future. + * NEWS: Mention to look at configure --help. + + Unrelated: + + * profile.c (pprint): Use "rule(s)" instead of "block(s)" in the + header. + +2014-09-23 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (yylex): Don't check for junk characters inside + quoted strings. Caused issues on DJGPP and Solaris. + + Unrelated: + + * io.c (devopen): Straighten things out with respect to + compatibility with BWK awk. + 2014-09-19 Arnold D. Robbins <arnold@skeeve.com> * awkgram.y: Further commentary as to the treacherousness @@ -24,6 +183,45 @@ since use of isalnum() let non-ASCII letters slip through into identifiers. +2014-09-13 Stephen Davies <sdavies@sdc.com.au> + + When doing pretty-printing (but not profiling), include the original + comments in the output. + + General rules: + + Pretty printing: + - Do NOT indent by a tab + - Do NOT print the header comments ("# BEGIN rules", etc.) + - DO print the comments that are in the program + + Profiling: + - DO indent by a tab + - DO print the header comments + - Do NOT print the program's original comments + + * awkgram.y (comment0, commentf): New varibles that are pointers to + program and function comments. + (get_comment): New function that retrieves consecutive comment lines + and empty lines as a unit). + (split_comment): New function: iff first block in the program is a + function and it is predeeded by comments, take the last non-blank + line as function comment and any preceeding lines as program comment.) + + Following token rules were changed to handle comments: + + * awkgram.y (pattern, LEX_BEGIN, LEX_END, LEX_BEGINFILE, LEX_ENDFILE, + action, function_prologue, statements): Update to handle comments. + + Following functions were changed to handle comments: + + * awkgram.y (mk_program, mk_function, allow_newline and yylex): Update + to handle comments. (Also fixed typo in case '\\'.) + + * profile.c (print_comment): New function to format comment printing. + (indent, pprint, dump_prog, pp_func): Changed to handle comments and + the revised indentation rules. + 2014-09-07 Arnold D. Robbins <arnold@skeeve.com> * awk.h: Move libsigsegv stuff to ... @@ -931,6 +1129,24 @@ * debug.c (print_memory): Fix whitespace / indentation. +2013-08-02 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (append_rule): Add attempt to insert any comment + before a rule. Commented out at the moment. + +2013-07-30 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (enum opcodeval): Add Op_comment. + * awkgram.y (comment): New variable to hold comment text. + (statement): Add saved comments to lists being built. + (allow_newline): Save comment text if necessary. Append if have + existing text. + (yylex): Ditto. + * debug.c (print_instruction): Handle Op_comment. + * eval.c (optypes): Add entry for Op_comment. + * interpret.h (r_interpret): Ditto. + * profile.c (pprint): For Op_comment, print the comment text. + 2013-07-24 Arnold D. Robbins <arnold@skeeve.com> * io.c (FAKE_FD_VALUE): Move definition from here ... diff --git a/Makefile.am b/Makefile.am index 3d1c8837..afe617ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -69,6 +69,7 @@ SUBDIRS = \ awklib \ po \ extension \ + extras \ test # what to make and install diff --git a/Makefile.in b/Makefile.in index 5c2a7f11..16d19b02 100644 --- a/Makefile.in +++ b/Makefile.in @@ -475,6 +475,7 @@ SUBDIRS = \ awklib \ po \ extension \ + extras \ test include_HEADERS = gawkapi.h @@ -34,6 +34,15 @@ Changes from 4.1.x to 4.2.0 8. MirBSD is no longer supported. +9. Pretty printing now preserves comments and places them into the + pretty-printed file. + +10. `make install' now installs shell startup files + $sysconfdir/profile.d/gawk.{csh,sh} containing shell functions to + manipulate the AWKPATH and AWKLIBPATH environment variables. On a Fedora + system, these files belong in /etc/profile.d, but the appropriate location + may be different on other platforms. + Changes from 4.1.1 to 4.1.2 --------------------------- @@ -57,6 +66,18 @@ Changes from 4.1.1 to 4.1.2 beside those of the English alphabet in identifiers. This has been fixed. (isalpha and isalnum are NOT our friends.) + If you feel that you must have this misfeature, use `configure --help' + to see what option to use when configuring gawk to reenable it. + +7. The "where" command has been added to the debugger as an alias + for "backtrace". This will make life easier for long-time GDB users. + +8. Gawk no longer explicitly checks the current directory after doing + a path search of AWKPATH. The default value continues to have "." at + the front, so most people should not be affected. If you have your own + AWKPATH setting, be sure to put "." in it somewhere. The documentation + has been updated and clarified. + XX. A number of bugs have been fixed. See the ChangeLog. Changes from 4.1.0 to 4.1.1 @@ -91,9 +91,6 @@ OS/2: andreas.buening@nexgo.de VMS: - Pat Rankin - r.pat.rankin@gmail.com - John Malmberg wb8tyw@qsl.net @@ -1,13 +1,9 @@ -Sun Aug 24 20:00:53 IDT 2014 +Sun Sep 28 22:19:10 IDT 2014 ============================ There were too many files tracking different thoughts and ideas for things to do, or consider doing. This file merges them into one. As -tasks are completed, they should be moved to the DONE section, below, -or simply removed. - -Upon creation of a release (major or patch release), items from the -previous release should be removed. +tasks are completed, they should be removed. This file should exist only in the master branch or branches based off of it for development, but not in the stable branch. This may require some @@ -23,9 +19,6 @@ Minor Cleanups and Code Improvements order to nuke the use of libtool. [ Partially started in the nolibtool branch. ] - Enhance profiling to save comments in a byte-code that does nothing - but that can be used when pretty printing the program. - API: ??? #if !defined(GAWK) && !defined(GAWK_OMIT_CONVENIENCE_MACROS) @@ -43,6 +36,8 @@ Minor Cleanups and Code Improvements Minor New Features ------------------ + Enable command line source text in the debugger. + Enhance extension/fork.c waitpid to allow the caller to specify the options. And add an optional array argument to wait and waitpid in which to return exit status information. @@ -146,18 +141,6 @@ Things To Think About That May Never Happen E.g., a length of 0 or -1 or something. Maybe "n"? -DONE -==== - -Minor Cleanups and Code Improvements ------------------------------------- - -Minor New Features ------------------- - -Major New Features ------------------- - Things That We Decided We Will Never Do ======================================= @@ -668,6 +668,7 @@ typedef enum opcodeval { Op_func, + Op_comment, /* for pretty printing */ Op_exec_count, Op_breakpoint, Op_lint, @@ -127,6 +127,7 @@ static void check_funcs(void); static ssize_t read_one_line(int fd, void *buffer, size_t count); static int one_line_close(int fd); +static void split_comment(void); static bool want_source = false; static bool want_regexp = false; /* lexical scanning kludge */ @@ -187,6 +188,12 @@ static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; INSTRUCTION *main_beginfile; +static INSTRUCTION *comment = NULL; +static INSTRUCTION *program_comment = NULL; +static INSTRUCTION *function_comment = NULL; + +static bool func_first = true; + static inline INSTRUCTION *list_create(INSTRUCTION *x); static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x); static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x); @@ -196,7 +203,7 @@ extern double fmod(double x, double y); #define YYSTYPE INSTRUCTION * -#line 200 "awkgram.c" /* yacc.c:339 */ +#line 207 "awkgram.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -350,7 +357,7 @@ int yyparse (void); /* Copy the second part of user declarations. */ -#line 354 "awkgram.c" /* yacc.c:358 */ +#line 361 "awkgram.c" /* yacc.c:358 */ #ifdef short # undef short @@ -652,25 +659,25 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 199, 199, 201, 206, 207, 213, 225, 229, 240, - 246, 251, 259, 267, 269, 274, 282, 284, 290, 291, - 293, 319, 330, 341, 347, 356, 366, 368, 370, 376, - 381, 382, 386, 405, 404, 438, 440, 445, 446, 459, - 464, 465, 469, 471, 473, 480, 570, 612, 654, 767, - 774, 781, 791, 800, 809, 818, 829, 845, 844, 868, - 880, 880, 978, 978, 1011, 1041, 1047, 1048, 1054, 1055, - 1062, 1067, 1079, 1093, 1095, 1103, 1108, 1110, 1118, 1120, - 1129, 1130, 1138, 1143, 1143, 1154, 1158, 1166, 1167, 1170, - 1172, 1177, 1178, 1187, 1188, 1193, 1198, 1204, 1206, 1208, - 1215, 1216, 1222, 1223, 1228, 1230, 1235, 1237, 1245, 1250, - 1259, 1266, 1268, 1270, 1286, 1296, 1303, 1305, 1310, 1312, - 1314, 1322, 1324, 1329, 1331, 1336, 1338, 1340, 1390, 1392, - 1394, 1396, 1398, 1400, 1402, 1404, 1418, 1423, 1428, 1453, - 1459, 1461, 1463, 1465, 1467, 1469, 1474, 1478, 1510, 1512, - 1518, 1524, 1537, 1538, 1539, 1544, 1549, 1553, 1557, 1572, - 1585, 1590, 1626, 1644, 1645, 1651, 1652, 1657, 1659, 1666, - 1683, 1700, 1702, 1709, 1714, 1722, 1732, 1744, 1753, 1757, - 1761, 1765, 1769, 1773, 1776, 1778, 1782, 1786, 1790 + 0, 206, 206, 208, 213, 214, 220, 232, 236, 247, + 253, 258, 266, 274, 276, 281, 289, 291, 297, 305, + 315, 341, 354, 367, 374, 384, 396, 398, 400, 406, + 411, 412, 416, 451, 450, 484, 486, 491, 497, 525, + 530, 531, 535, 537, 539, 546, 636, 678, 720, 833, + 840, 847, 857, 866, 875, 884, 895, 911, 910, 934, + 946, 946, 1044, 1044, 1077, 1107, 1113, 1114, 1120, 1121, + 1128, 1133, 1145, 1159, 1161, 1169, 1174, 1176, 1184, 1186, + 1195, 1196, 1204, 1209, 1209, 1220, 1224, 1232, 1233, 1236, + 1238, 1243, 1244, 1253, 1254, 1259, 1264, 1270, 1272, 1274, + 1281, 1282, 1288, 1289, 1294, 1296, 1301, 1303, 1311, 1316, + 1325, 1332, 1334, 1336, 1352, 1362, 1369, 1371, 1376, 1378, + 1380, 1388, 1390, 1395, 1397, 1402, 1404, 1406, 1456, 1458, + 1460, 1462, 1464, 1466, 1468, 1470, 1484, 1489, 1494, 1519, + 1525, 1527, 1529, 1531, 1533, 1535, 1540, 1544, 1576, 1578, + 1584, 1590, 1603, 1604, 1605, 1610, 1615, 1619, 1623, 1638, + 1651, 1656, 1692, 1710, 1711, 1717, 1718, 1723, 1725, 1732, + 1749, 1766, 1768, 1775, 1780, 1788, 1798, 1810, 1819, 1823, + 1827, 1831, 1835, 1839, 1842, 1844, 1848, 1852, 1856 }; #endif @@ -1843,26 +1850,26 @@ yyreduce: switch (yyn) { case 3: -#line 202 "awkgram.y" /* yacc.c:1646 */ +#line 209 "awkgram.y" /* yacc.c:1646 */ { rule = 0; yyerrok; } -#line 1852 "awkgram.c" /* yacc.c:1646 */ +#line 1859 "awkgram.c" /* yacc.c:1646 */ break; case 5: -#line 208 "awkgram.y" /* yacc.c:1646 */ +#line 215 "awkgram.y" /* yacc.c:1646 */ { next_sourcefile(); if (sourcefile == srcfiles) process_deferred(); } -#line 1862 "awkgram.c" /* yacc.c:1646 */ +#line 1869 "awkgram.c" /* yacc.c:1646 */ break; case 6: -#line 214 "awkgram.y" /* yacc.c:1646 */ +#line 221 "awkgram.y" /* yacc.c:1646 */ { rule = 0; /* @@ -1871,19 +1878,19 @@ yyreduce: */ /* yyerrok; */ } -#line 1875 "awkgram.c" /* yacc.c:1646 */ +#line 1882 "awkgram.c" /* yacc.c:1646 */ break; case 7: -#line 226 "awkgram.y" /* yacc.c:1646 */ +#line 233 "awkgram.y" /* yacc.c:1646 */ { (void) append_rule((yyvsp[-1]), (yyvsp[0])); } -#line 1883 "awkgram.c" /* yacc.c:1646 */ +#line 1890 "awkgram.c" /* yacc.c:1646 */ break; case 8: -#line 230 "awkgram.y" /* yacc.c:1646 */ +#line 237 "awkgram.y" /* yacc.c:1646 */ { if (rule != Rule) { msg(_("%s blocks must have an action part"), ruletab[rule]); @@ -1894,39 +1901,39 @@ yyreduce: } else /* pattern rule with non-empty pattern */ (void) append_rule((yyvsp[-1]), NULL); } -#line 1898 "awkgram.c" /* yacc.c:1646 */ +#line 1905 "awkgram.c" /* yacc.c:1646 */ break; case 9: -#line 241 "awkgram.y" /* yacc.c:1646 */ +#line 248 "awkgram.y" /* yacc.c:1646 */ { in_function = NULL; (void) mk_function((yyvsp[-1]), (yyvsp[0])); yyerrok; } -#line 1908 "awkgram.c" /* yacc.c:1646 */ +#line 1915 "awkgram.c" /* yacc.c:1646 */ break; case 10: -#line 247 "awkgram.y" /* yacc.c:1646 */ +#line 254 "awkgram.y" /* yacc.c:1646 */ { want_source = false; yyerrok; } -#line 1917 "awkgram.c" /* yacc.c:1646 */ +#line 1924 "awkgram.c" /* yacc.c:1646 */ break; case 11: -#line 252 "awkgram.y" /* yacc.c:1646 */ +#line 259 "awkgram.y" /* yacc.c:1646 */ { want_source = false; yyerrok; } -#line 1926 "awkgram.c" /* yacc.c:1646 */ +#line 1933 "awkgram.c" /* yacc.c:1646 */ break; case 12: -#line 260 "awkgram.y" /* yacc.c:1646 */ +#line 267 "awkgram.y" /* yacc.c:1646 */ { if (include_source((yyvsp[0])) < 0) YYABORT; @@ -1934,23 +1941,23 @@ yyreduce: bcfree((yyvsp[0])); (yyval) = NULL; } -#line 1938 "awkgram.c" /* yacc.c:1646 */ +#line 1945 "awkgram.c" /* yacc.c:1646 */ break; case 13: -#line 268 "awkgram.y" /* yacc.c:1646 */ +#line 275 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 1944 "awkgram.c" /* yacc.c:1646 */ +#line 1951 "awkgram.c" /* yacc.c:1646 */ break; case 14: -#line 270 "awkgram.y" /* yacc.c:1646 */ +#line 277 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 1950 "awkgram.c" /* yacc.c:1646 */ +#line 1957 "awkgram.c" /* yacc.c:1646 */ break; case 15: -#line 275 "awkgram.y" /* yacc.c:1646 */ +#line 282 "awkgram.y" /* yacc.c:1646 */ { if (load_library((yyvsp[0])) < 0) YYABORT; @@ -1958,35 +1965,49 @@ yyreduce: bcfree((yyvsp[0])); (yyval) = NULL; } -#line 1962 "awkgram.c" /* yacc.c:1646 */ +#line 1969 "awkgram.c" /* yacc.c:1646 */ break; case 16: -#line 283 "awkgram.y" /* yacc.c:1646 */ +#line 290 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 1968 "awkgram.c" /* yacc.c:1646 */ +#line 1975 "awkgram.c" /* yacc.c:1646 */ break; case 17: -#line 285 "awkgram.y" /* yacc.c:1646 */ +#line 292 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 1974 "awkgram.c" /* yacc.c:1646 */ +#line 1981 "awkgram.c" /* yacc.c:1646 */ break; case 18: -#line 290 "awkgram.y" /* yacc.c:1646 */ - { (yyval) = NULL; rule = Rule; } -#line 1980 "awkgram.c" /* yacc.c:1646 */ +#line 297 "awkgram.y" /* yacc.c:1646 */ + { + rule = Rule; + if (comment != NULL) { + (yyval) = list_create(comment); + comment = NULL; + } else + (yyval) = NULL; + } +#line 1994 "awkgram.c" /* yacc.c:1646 */ break; case 19: -#line 292 "awkgram.y" /* yacc.c:1646 */ - { (yyval) = (yyvsp[0]); rule = Rule; } -#line 1986 "awkgram.c" /* yacc.c:1646 */ +#line 306 "awkgram.y" /* yacc.c:1646 */ + { + rule = Rule; + if (comment != NULL) { + (yyval) = list_prepend((yyvsp[0]), comment); + comment = NULL; + } else + (yyval) = (yyvsp[0]); + } +#line 2007 "awkgram.c" /* yacc.c:1646 */ break; case 20: -#line 294 "awkgram.y" /* yacc.c:1646 */ +#line 316 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *tp; @@ -2012,13 +2033,15 @@ yyreduce: (yyval) = list_append(list_merge((yyvsp[-3]), (yyvsp[0])), tp); rule = Rule; } -#line 2016 "awkgram.c" /* yacc.c:1646 */ +#line 2037 "awkgram.c" /* yacc.c:1646 */ break; case 21: -#line 320 "awkgram.y" /* yacc.c:1646 */ +#line 342 "awkgram.y" /* yacc.c:1646 */ { static int begin_seen = 0; + + func_first = false; if (do_lint_old && ++begin_seen == 2) warning_ln((yyvsp[0])->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -2027,13 +2050,15 @@ yyreduce: (yyvsp[0])->source_file = source; (yyval) = (yyvsp[0]); } -#line 2031 "awkgram.c" /* yacc.c:1646 */ +#line 2054 "awkgram.c" /* yacc.c:1646 */ break; case 22: -#line 331 "awkgram.y" /* yacc.c:1646 */ +#line 355 "awkgram.y" /* yacc.c:1646 */ { static int end_seen = 0; + + func_first = false; if (do_lint_old && ++end_seen == 2) warning_ln((yyvsp[0])->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -2042,71 +2067,91 @@ yyreduce: (yyvsp[0])->source_file = source; (yyval) = (yyvsp[0]); } -#line 2046 "awkgram.c" /* yacc.c:1646 */ +#line 2071 "awkgram.c" /* yacc.c:1646 */ break; case 23: -#line 342 "awkgram.y" /* yacc.c:1646 */ +#line 368 "awkgram.y" /* yacc.c:1646 */ { + func_first = false; (yyvsp[0])->in_rule = rule = BEGINFILE; (yyvsp[0])->source_file = source; (yyval) = (yyvsp[0]); } -#line 2056 "awkgram.c" /* yacc.c:1646 */ +#line 2082 "awkgram.c" /* yacc.c:1646 */ break; case 24: -#line 348 "awkgram.y" /* yacc.c:1646 */ +#line 375 "awkgram.y" /* yacc.c:1646 */ { + func_first = false; (yyvsp[0])->in_rule = rule = ENDFILE; (yyvsp[0])->source_file = source; (yyval) = (yyvsp[0]); } -#line 2066 "awkgram.c" /* yacc.c:1646 */ +#line 2093 "awkgram.c" /* yacc.c:1646 */ break; case 25: -#line 357 "awkgram.y" /* yacc.c:1646 */ +#line 385 "awkgram.y" /* yacc.c:1646 */ { + INSTRUCTION *ip; if ((yyvsp[-3]) == NULL) - (yyval) = list_create(instruction(Op_no_op)); + ip = list_create(instruction(Op_no_op)); else - (yyval) = (yyvsp[-3]); + ip = (yyvsp[-3]); + (yyval) = ip; } -#line 2077 "awkgram.c" /* yacc.c:1646 */ +#line 2106 "awkgram.c" /* yacc.c:1646 */ break; case 26: -#line 367 "awkgram.y" /* yacc.c:1646 */ +#line 397 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2083 "awkgram.c" /* yacc.c:1646 */ +#line 2112 "awkgram.c" /* yacc.c:1646 */ break; case 27: -#line 369 "awkgram.y" /* yacc.c:1646 */ +#line 399 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2089 "awkgram.c" /* yacc.c:1646 */ +#line 2118 "awkgram.c" /* yacc.c:1646 */ break; case 28: -#line 371 "awkgram.y" /* yacc.c:1646 */ +#line 401 "awkgram.y" /* yacc.c:1646 */ { yyerror(_("`%s' is a built-in function, it cannot be redefined"), tokstart); YYABORT; } -#line 2099 "awkgram.c" /* yacc.c:1646 */ +#line 2128 "awkgram.c" /* yacc.c:1646 */ break; case 29: -#line 377 "awkgram.y" /* yacc.c:1646 */ +#line 407 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2105 "awkgram.c" /* yacc.c:1646 */ +#line 2134 "awkgram.c" /* yacc.c:1646 */ break; case 32: -#line 387 "awkgram.y" /* yacc.c:1646 */ +#line 417 "awkgram.y" /* yacc.c:1646 */ { + /* + * treat any comments between BOF and the first function + * definition (with no intervening BEGIN etc block) as + * program comments. Special kludge: iff there are more + * than one such comments, treat the last as a function + * comment. + */ + if (comment != NULL && func_first + && strstr(comment->memory->stptr, "\n\n") != NULL) + split_comment(); + /* save any other pre-function comment as function comment */ + if (comment != NULL) { + function_comment = comment; + comment = NULL; + } + func_first = false; (yyvsp[-5])->source_file = source; if (install_function((yyvsp[-4])->lextok, (yyvsp[-5]), (yyvsp[-2])) < 0) YYABORT; @@ -2116,17 +2161,17 @@ yyreduce: /* $4 already free'd in install_function */ (yyval) = (yyvsp[-5]); } -#line 2120 "awkgram.c" /* yacc.c:1646 */ +#line 2165 "awkgram.c" /* yacc.c:1646 */ break; case 33: -#line 405 "awkgram.y" /* yacc.c:1646 */ +#line 451 "awkgram.y" /* yacc.c:1646 */ { want_regexp = true; } -#line 2126 "awkgram.c" /* yacc.c:1646 */ +#line 2171 "awkgram.c" /* yacc.c:1646 */ break; case 34: -#line 407 "awkgram.y" /* yacc.c:1646 */ +#line 453 "awkgram.y" /* yacc.c:1646 */ { NODE *n, *exp; char *re; @@ -2155,69 +2200,89 @@ yyreduce: (yyval)->opcode = Op_match_rec; (yyval)->memory = n; } -#line 2159 "awkgram.c" /* yacc.c:1646 */ +#line 2204 "awkgram.c" /* yacc.c:1646 */ break; case 35: -#line 439 "awkgram.y" /* yacc.c:1646 */ +#line 485 "awkgram.y" /* yacc.c:1646 */ { bcfree((yyvsp[0])); } -#line 2165 "awkgram.c" /* yacc.c:1646 */ +#line 2210 "awkgram.c" /* yacc.c:1646 */ break; case 37: -#line 445 "awkgram.y" /* yacc.c:1646 */ - { (yyval) = NULL; } -#line 2171 "awkgram.c" /* yacc.c:1646 */ +#line 491 "awkgram.y" /* yacc.c:1646 */ + { + if (comment != NULL) { + (yyval) = list_create(comment); + comment = NULL; + } else (yyval) = NULL; + } +#line 2221 "awkgram.c" /* yacc.c:1646 */ break; case 38: -#line 447 "awkgram.y" /* yacc.c:1646 */ +#line 498 "awkgram.y" /* yacc.c:1646 */ { - if ((yyvsp[0]) == NULL) - (yyval) = (yyvsp[-1]); - else { + if ((yyvsp[0]) == NULL) { + if (comment == NULL) + (yyval) = (yyvsp[-1]); + else { + (yyval) = list_append((yyvsp[-1]), comment); + comment = NULL; + } + } else { add_lint((yyvsp[0]), LINT_no_effect); - if ((yyvsp[-1]) == NULL) - (yyval) = (yyvsp[0]); - else + if ((yyvsp[-1]) == NULL) { + if (comment == NULL) + (yyval) = (yyvsp[0]); + else { + (yyval) = list_append((yyvsp[0]), comment); + comment = NULL; + } + } else { + if (comment != NULL) { + list_append((yyvsp[0]), comment); + comment = NULL; + } (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); + } } - yyerrok; + yyerrok; } -#line 2188 "awkgram.c" /* yacc.c:1646 */ +#line 2253 "awkgram.c" /* yacc.c:1646 */ break; case 39: -#line 460 "awkgram.y" /* yacc.c:1646 */ +#line 526 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 2194 "awkgram.c" /* yacc.c:1646 */ +#line 2259 "awkgram.c" /* yacc.c:1646 */ break; case 42: -#line 470 "awkgram.y" /* yacc.c:1646 */ +#line 536 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 2200 "awkgram.c" /* yacc.c:1646 */ +#line 2265 "awkgram.c" /* yacc.c:1646 */ break; case 43: -#line 472 "awkgram.y" /* yacc.c:1646 */ +#line 538 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 2206 "awkgram.c" /* yacc.c:1646 */ +#line 2271 "awkgram.c" /* yacc.c:1646 */ break; case 44: -#line 474 "awkgram.y" /* yacc.c:1646 */ +#line 540 "awkgram.y" /* yacc.c:1646 */ { if (do_pretty_print) (yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count)); else (yyval) = (yyvsp[0]); } -#line 2217 "awkgram.c" /* yacc.c:1646 */ +#line 2282 "awkgram.c" /* yacc.c:1646 */ break; case 45: -#line 481 "awkgram.y" /* yacc.c:1646 */ +#line 547 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt; INSTRUCTION *ip, *nextc, *tbreak; @@ -2238,7 +2303,7 @@ yyreduce: } /* else curr = NULL; */ - for(; curr != NULL; curr = nextc) { + for (; curr != NULL; curr = nextc) { INSTRUCTION *caseexp = curr->case_exp; INSTRUCTION *casestmt = curr->case_stmt; @@ -2307,11 +2372,11 @@ yyreduce: break_allowed--; fix_break_continue(ip, tbreak, NULL); } -#line 2311 "awkgram.c" /* yacc.c:1646 */ +#line 2376 "awkgram.c" /* yacc.c:1646 */ break; case 46: -#line 571 "awkgram.y" /* yacc.c:1646 */ +#line 637 "awkgram.y" /* yacc.c:1646 */ { /* * ----------------- @@ -2353,11 +2418,11 @@ yyreduce: continue_allowed--; fix_break_continue(ip, tbreak, tcont); } -#line 2357 "awkgram.c" /* yacc.c:1646 */ +#line 2422 "awkgram.c" /* yacc.c:1646 */ break; case 47: -#line 613 "awkgram.y" /* yacc.c:1646 */ +#line 679 "awkgram.y" /* yacc.c:1646 */ { /* * ----------------- @@ -2399,11 +2464,11 @@ yyreduce: } /* else $1 and $4 are NULLs */ } -#line 2403 "awkgram.c" /* yacc.c:1646 */ +#line 2468 "awkgram.c" /* yacc.c:1646 */ break; case 48: -#line 655 "awkgram.y" /* yacc.c:1646 */ +#line 721 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *ip; char *var_name = (yyvsp[-5])->lextok; @@ -2516,44 +2581,44 @@ regular_loop: break_allowed--; continue_allowed--; } -#line 2520 "awkgram.c" /* yacc.c:1646 */ +#line 2585 "awkgram.c" /* yacc.c:1646 */ break; case 49: -#line 768 "awkgram.y" /* yacc.c:1646 */ +#line 834 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_for_loop((yyvsp[-11]), (yyvsp[-9]), (yyvsp[-6]), (yyvsp[-3]), (yyvsp[0])); break_allowed--; continue_allowed--; } -#line 2531 "awkgram.c" /* yacc.c:1646 */ +#line 2596 "awkgram.c" /* yacc.c:1646 */ break; case 50: -#line 775 "awkgram.y" /* yacc.c:1646 */ +#line 841 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_for_loop((yyvsp[-10]), (yyvsp[-8]), (INSTRUCTION *) NULL, (yyvsp[-3]), (yyvsp[0])); break_allowed--; continue_allowed--; } -#line 2542 "awkgram.c" /* yacc.c:1646 */ +#line 2607 "awkgram.c" /* yacc.c:1646 */ break; case 51: -#line 782 "awkgram.y" /* yacc.c:1646 */ +#line 848 "awkgram.y" /* yacc.c:1646 */ { if (do_pretty_print) (yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count)); else (yyval) = (yyvsp[0]); } -#line 2553 "awkgram.c" /* yacc.c:1646 */ +#line 2618 "awkgram.c" /* yacc.c:1646 */ break; case 52: -#line 792 "awkgram.y" /* yacc.c:1646 */ +#line 858 "awkgram.y" /* yacc.c:1646 */ { if (! break_allowed) error_ln((yyvsp[-1])->source_line, @@ -2562,11 +2627,11 @@ regular_loop: (yyval) = list_create((yyvsp[-1])); } -#line 2566 "awkgram.c" /* yacc.c:1646 */ +#line 2631 "awkgram.c" /* yacc.c:1646 */ break; case 53: -#line 801 "awkgram.y" /* yacc.c:1646 */ +#line 867 "awkgram.y" /* yacc.c:1646 */ { if (! continue_allowed) error_ln((yyvsp[-1])->source_line, @@ -2575,11 +2640,11 @@ regular_loop: (yyval) = list_create((yyvsp[-1])); } -#line 2579 "awkgram.c" /* yacc.c:1646 */ +#line 2644 "awkgram.c" /* yacc.c:1646 */ break; case 54: -#line 810 "awkgram.y" /* yacc.c:1646 */ +#line 876 "awkgram.y" /* yacc.c:1646 */ { /* if inside function (rule = 0), resolve context at run-time */ if (rule && rule != Rule) @@ -2588,11 +2653,11 @@ regular_loop: (yyvsp[-1])->target_jmp = ip_rec; (yyval) = list_create((yyvsp[-1])); } -#line 2592 "awkgram.c" /* yacc.c:1646 */ +#line 2657 "awkgram.c" /* yacc.c:1646 */ break; case 55: -#line 819 "awkgram.y" /* yacc.c:1646 */ +#line 885 "awkgram.y" /* yacc.c:1646 */ { /* if inside function (rule = 0), resolve context at run-time */ if (rule == BEGIN || rule == END || rule == ENDFILE) @@ -2603,11 +2668,11 @@ regular_loop: (yyvsp[-1])->target_endfile = ip_endfile; (yyval) = list_create((yyvsp[-1])); } -#line 2607 "awkgram.c" /* yacc.c:1646 */ +#line 2672 "awkgram.c" /* yacc.c:1646 */ break; case 56: -#line 830 "awkgram.y" /* yacc.c:1646 */ +#line 896 "awkgram.y" /* yacc.c:1646 */ { /* Initialize the two possible jump targets, the actual target * is resolved at run-time. @@ -2622,20 +2687,20 @@ regular_loop: } else (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); } -#line 2626 "awkgram.c" /* yacc.c:1646 */ +#line 2691 "awkgram.c" /* yacc.c:1646 */ break; case 57: -#line 845 "awkgram.y" /* yacc.c:1646 */ +#line 911 "awkgram.y" /* yacc.c:1646 */ { if (! in_function) yyerror(_("`return' used outside function context")); } -#line 2635 "awkgram.c" /* yacc.c:1646 */ +#line 2700 "awkgram.c" /* yacc.c:1646 */ break; case 58: -#line 848 "awkgram.y" /* yacc.c:1646 */ +#line 914 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[-1]) == NULL) { (yyval) = list_create((yyvsp[-3])); @@ -2656,17 +2721,17 @@ regular_loop: (yyval) = list_append((yyvsp[-1]), (yyvsp[-3])); } } -#line 2660 "awkgram.c" /* yacc.c:1646 */ +#line 2725 "awkgram.c" /* yacc.c:1646 */ break; case 60: -#line 880 "awkgram.y" /* yacc.c:1646 */ +#line 946 "awkgram.y" /* yacc.c:1646 */ { in_print = true; in_parens = 0; } -#line 2666 "awkgram.c" /* yacc.c:1646 */ +#line 2731 "awkgram.c" /* yacc.c:1646 */ break; case 61: -#line 881 "awkgram.y" /* yacc.c:1646 */ +#line 947 "awkgram.y" /* yacc.c:1646 */ { /* * Optimization: plain `print' has no expression list, so $3 is null. @@ -2763,17 +2828,17 @@ regular_print: } } } -#line 2767 "awkgram.c" /* yacc.c:1646 */ +#line 2832 "awkgram.c" /* yacc.c:1646 */ break; case 62: -#line 978 "awkgram.y" /* yacc.c:1646 */ +#line 1044 "awkgram.y" /* yacc.c:1646 */ { sub_counter = 0; } -#line 2773 "awkgram.c" /* yacc.c:1646 */ +#line 2838 "awkgram.c" /* yacc.c:1646 */ break; case 63: -#line 979 "awkgram.y" /* yacc.c:1646 */ +#line 1045 "awkgram.y" /* yacc.c:1646 */ { char *arr = (yyvsp[-2])->lextok; @@ -2806,11 +2871,11 @@ regular_print: (yyval) = list_append(list_append((yyvsp[0]), (yyvsp[-2])), (yyvsp[-3])); } } -#line 2810 "awkgram.c" /* yacc.c:1646 */ +#line 2875 "awkgram.c" /* yacc.c:1646 */ break; case 64: -#line 1016 "awkgram.y" /* yacc.c:1646 */ +#line 1082 "awkgram.y" /* yacc.c:1646 */ { static bool warned = false; char *arr = (yyvsp[-1])->lextok; @@ -2836,52 +2901,52 @@ regular_print: fatal(_("`delete' is not allowed with FUNCTAB")); } } -#line 2840 "awkgram.c" /* yacc.c:1646 */ +#line 2905 "awkgram.c" /* yacc.c:1646 */ break; case 65: -#line 1042 "awkgram.y" /* yacc.c:1646 */ +#line 1108 "awkgram.y" /* yacc.c:1646 */ { (yyval) = optimize_assignment((yyvsp[0])); } -#line 2846 "awkgram.c" /* yacc.c:1646 */ +#line 2911 "awkgram.c" /* yacc.c:1646 */ break; case 66: -#line 1047 "awkgram.y" /* yacc.c:1646 */ +#line 1113 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 2852 "awkgram.c" /* yacc.c:1646 */ +#line 2917 "awkgram.c" /* yacc.c:1646 */ break; case 67: -#line 1049 "awkgram.y" /* yacc.c:1646 */ +#line 1115 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2858 "awkgram.c" /* yacc.c:1646 */ +#line 2923 "awkgram.c" /* yacc.c:1646 */ break; case 68: -#line 1054 "awkgram.y" /* yacc.c:1646 */ +#line 1120 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 2864 "awkgram.c" /* yacc.c:1646 */ +#line 2929 "awkgram.c" /* yacc.c:1646 */ break; case 69: -#line 1056 "awkgram.y" /* yacc.c:1646 */ +#line 1122 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[-1]) == NULL) (yyval) = list_create((yyvsp[0])); else (yyval) = list_prepend((yyvsp[-1]), (yyvsp[0])); } -#line 2875 "awkgram.c" /* yacc.c:1646 */ +#line 2940 "awkgram.c" /* yacc.c:1646 */ break; case 70: -#line 1063 "awkgram.y" /* yacc.c:1646 */ +#line 1129 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 2881 "awkgram.c" /* yacc.c:1646 */ +#line 2946 "awkgram.c" /* yacc.c:1646 */ break; case 71: -#line 1068 "awkgram.y" /* yacc.c:1646 */ +#line 1134 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *casestmt = (yyvsp[0]); if ((yyvsp[0]) == NULL) @@ -2893,11 +2958,11 @@ regular_print: bcfree((yyvsp[-2])); (yyval) = (yyvsp[-4]); } -#line 2897 "awkgram.c" /* yacc.c:1646 */ +#line 2962 "awkgram.c" /* yacc.c:1646 */ break; case 72: -#line 1080 "awkgram.y" /* yacc.c:1646 */ +#line 1146 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *casestmt = (yyvsp[0]); if ((yyvsp[0]) == NULL) @@ -2908,17 +2973,17 @@ regular_print: (yyvsp[-3])->case_stmt = casestmt; (yyval) = (yyvsp[-3]); } -#line 2912 "awkgram.c" /* yacc.c:1646 */ +#line 2977 "awkgram.c" /* yacc.c:1646 */ break; case 73: -#line 1094 "awkgram.y" /* yacc.c:1646 */ +#line 1160 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2918 "awkgram.c" /* yacc.c:1646 */ +#line 2983 "awkgram.c" /* yacc.c:1646 */ break; case 74: -#line 1096 "awkgram.y" /* yacc.c:1646 */ +#line 1162 "awkgram.y" /* yacc.c:1646 */ { NODE *n = (yyvsp[0])->memory; (void) force_number(n); @@ -2926,71 +2991,71 @@ regular_print: bcfree((yyvsp[-1])); (yyval) = (yyvsp[0]); } -#line 2930 "awkgram.c" /* yacc.c:1646 */ +#line 2995 "awkgram.c" /* yacc.c:1646 */ break; case 75: -#line 1104 "awkgram.y" /* yacc.c:1646 */ +#line 1170 "awkgram.y" /* yacc.c:1646 */ { bcfree((yyvsp[-1])); (yyval) = (yyvsp[0]); } -#line 2939 "awkgram.c" /* yacc.c:1646 */ +#line 3004 "awkgram.c" /* yacc.c:1646 */ break; case 76: -#line 1109 "awkgram.y" /* yacc.c:1646 */ +#line 1175 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2945 "awkgram.c" /* yacc.c:1646 */ +#line 3010 "awkgram.c" /* yacc.c:1646 */ break; case 77: -#line 1111 "awkgram.y" /* yacc.c:1646 */ +#line 1177 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_push_re; (yyval) = (yyvsp[0]); } -#line 2954 "awkgram.c" /* yacc.c:1646 */ +#line 3019 "awkgram.c" /* yacc.c:1646 */ break; case 78: -#line 1119 "awkgram.y" /* yacc.c:1646 */ +#line 1185 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2960 "awkgram.c" /* yacc.c:1646 */ +#line 3025 "awkgram.c" /* yacc.c:1646 */ break; case 79: -#line 1121 "awkgram.y" /* yacc.c:1646 */ +#line 1187 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 2966 "awkgram.c" /* yacc.c:1646 */ +#line 3031 "awkgram.c" /* yacc.c:1646 */ break; case 81: -#line 1131 "awkgram.y" /* yacc.c:1646 */ +#line 1197 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 2974 "awkgram.c" /* yacc.c:1646 */ +#line 3039 "awkgram.c" /* yacc.c:1646 */ break; case 82: -#line 1138 "awkgram.y" /* yacc.c:1646 */ +#line 1204 "awkgram.y" /* yacc.c:1646 */ { in_print = false; in_parens = 0; (yyval) = NULL; } -#line 2984 "awkgram.c" /* yacc.c:1646 */ +#line 3049 "awkgram.c" /* yacc.c:1646 */ break; case 83: -#line 1143 "awkgram.y" /* yacc.c:1646 */ +#line 1209 "awkgram.y" /* yacc.c:1646 */ { in_print = false; in_parens = 0; } -#line 2990 "awkgram.c" /* yacc.c:1646 */ +#line 3055 "awkgram.c" /* yacc.c:1646 */ break; case 84: -#line 1144 "awkgram.y" /* yacc.c:1646 */ +#line 1210 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[-2])->redir_type == redirect_twoway && (yyvsp[0])->lasti->opcode == Op_K_getline_redir @@ -2998,136 +3063,136 @@ regular_print: yyerror(_("multistage two-way pipelines don't work")); (yyval) = list_prepend((yyvsp[0]), (yyvsp[-2])); } -#line 3002 "awkgram.c" /* yacc.c:1646 */ +#line 3067 "awkgram.c" /* yacc.c:1646 */ break; case 85: -#line 1155 "awkgram.y" /* yacc.c:1646 */ +#line 1221 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_condition((yyvsp[-3]), (yyvsp[-5]), (yyvsp[0]), NULL, NULL); } -#line 3010 "awkgram.c" /* yacc.c:1646 */ +#line 3075 "awkgram.c" /* yacc.c:1646 */ break; case 86: -#line 1160 "awkgram.y" /* yacc.c:1646 */ +#line 1226 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_condition((yyvsp[-6]), (yyvsp[-8]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[0])); } -#line 3018 "awkgram.c" /* yacc.c:1646 */ +#line 3083 "awkgram.c" /* yacc.c:1646 */ break; case 91: -#line 1177 "awkgram.y" /* yacc.c:1646 */ +#line 1243 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3024 "awkgram.c" /* yacc.c:1646 */ +#line 3089 "awkgram.c" /* yacc.c:1646 */ break; case 92: -#line 1179 "awkgram.y" /* yacc.c:1646 */ +#line 1245 "awkgram.y" /* yacc.c:1646 */ { bcfree((yyvsp[-1])); (yyval) = (yyvsp[0]); } -#line 3033 "awkgram.c" /* yacc.c:1646 */ +#line 3098 "awkgram.c" /* yacc.c:1646 */ break; case 93: -#line 1187 "awkgram.y" /* yacc.c:1646 */ +#line 1253 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3039 "awkgram.c" /* yacc.c:1646 */ +#line 3104 "awkgram.c" /* yacc.c:1646 */ break; case 94: -#line 1189 "awkgram.y" /* yacc.c:1646 */ - { (yyval) = (yyvsp[0]) ; } -#line 3045 "awkgram.c" /* yacc.c:1646 */ +#line 1255 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3110 "awkgram.c" /* yacc.c:1646 */ break; case 95: -#line 1194 "awkgram.y" /* yacc.c:1646 */ +#line 1260 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->param_count = 0; (yyval) = list_create((yyvsp[0])); } -#line 3054 "awkgram.c" /* yacc.c:1646 */ +#line 3119 "awkgram.c" /* yacc.c:1646 */ break; case 96: -#line 1199 "awkgram.y" /* yacc.c:1646 */ +#line 1265 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->param_count = (yyvsp[-2])->lasti->param_count + 1; (yyval) = list_append((yyvsp[-2]), (yyvsp[0])); yyerrok; } -#line 3064 "awkgram.c" /* yacc.c:1646 */ +#line 3129 "awkgram.c" /* yacc.c:1646 */ break; case 97: -#line 1205 "awkgram.y" /* yacc.c:1646 */ +#line 1271 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3070 "awkgram.c" /* yacc.c:1646 */ +#line 3135 "awkgram.c" /* yacc.c:1646 */ break; case 98: -#line 1207 "awkgram.y" /* yacc.c:1646 */ +#line 1273 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 3076 "awkgram.c" /* yacc.c:1646 */ +#line 3141 "awkgram.c" /* yacc.c:1646 */ break; case 99: -#line 1209 "awkgram.y" /* yacc.c:1646 */ +#line 1275 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-2]); } -#line 3082 "awkgram.c" /* yacc.c:1646 */ +#line 3147 "awkgram.c" /* yacc.c:1646 */ break; case 100: -#line 1215 "awkgram.y" /* yacc.c:1646 */ +#line 1281 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3088 "awkgram.c" /* yacc.c:1646 */ +#line 3153 "awkgram.c" /* yacc.c:1646 */ break; case 101: -#line 1217 "awkgram.y" /* yacc.c:1646 */ +#line 1283 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3094 "awkgram.c" /* yacc.c:1646 */ +#line 3159 "awkgram.c" /* yacc.c:1646 */ break; case 102: -#line 1222 "awkgram.y" /* yacc.c:1646 */ +#line 1288 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3100 "awkgram.c" /* yacc.c:1646 */ +#line 3165 "awkgram.c" /* yacc.c:1646 */ break; case 103: -#line 1224 "awkgram.y" /* yacc.c:1646 */ +#line 1290 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3106 "awkgram.c" /* yacc.c:1646 */ +#line 3171 "awkgram.c" /* yacc.c:1646 */ break; case 104: -#line 1229 "awkgram.y" /* yacc.c:1646 */ +#line 1295 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_expression_list(NULL, (yyvsp[0])); } -#line 3112 "awkgram.c" /* yacc.c:1646 */ +#line 3177 "awkgram.c" /* yacc.c:1646 */ break; case 105: -#line 1231 "awkgram.y" /* yacc.c:1646 */ +#line 1297 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); yyerrok; } -#line 3121 "awkgram.c" /* yacc.c:1646 */ +#line 3186 "awkgram.c" /* yacc.c:1646 */ break; case 106: -#line 1236 "awkgram.y" /* yacc.c:1646 */ +#line 1302 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3127 "awkgram.c" /* yacc.c:1646 */ +#line 3192 "awkgram.c" /* yacc.c:1646 */ break; case 107: -#line 1238 "awkgram.y" /* yacc.c:1646 */ +#line 1304 "awkgram.y" /* yacc.c:1646 */ { /* * Returning the expression list instead of NULL lets @@ -3135,52 +3200,52 @@ regular_print: */ (yyval) = (yyvsp[-1]); } -#line 3139 "awkgram.c" /* yacc.c:1646 */ +#line 3204 "awkgram.c" /* yacc.c:1646 */ break; case 108: -#line 1246 "awkgram.y" /* yacc.c:1646 */ +#line 1312 "awkgram.y" /* yacc.c:1646 */ { /* Ditto */ (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); } -#line 3148 "awkgram.c" /* yacc.c:1646 */ +#line 3213 "awkgram.c" /* yacc.c:1646 */ break; case 109: -#line 1251 "awkgram.y" /* yacc.c:1646 */ +#line 1317 "awkgram.y" /* yacc.c:1646 */ { /* Ditto */ (yyval) = (yyvsp[-2]); } -#line 3157 "awkgram.c" /* yacc.c:1646 */ +#line 3222 "awkgram.c" /* yacc.c:1646 */ break; case 110: -#line 1260 "awkgram.y" /* yacc.c:1646 */ +#line 1326 "awkgram.y" /* yacc.c:1646 */ { if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec) lintwarn_ln((yyvsp[-1])->source_line, _("regular expression on right of assignment")); (yyval) = mk_assignment((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3168 "awkgram.c" /* yacc.c:1646 */ +#line 3233 "awkgram.c" /* yacc.c:1646 */ break; case 111: -#line 1267 "awkgram.y" /* yacc.c:1646 */ +#line 1333 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3174 "awkgram.c" /* yacc.c:1646 */ +#line 3239 "awkgram.c" /* yacc.c:1646 */ break; case 112: -#line 1269 "awkgram.y" /* yacc.c:1646 */ +#line 1335 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3180 "awkgram.c" /* yacc.c:1646 */ +#line 3245 "awkgram.c" /* yacc.c:1646 */ break; case 113: -#line 1271 "awkgram.y" /* yacc.c:1646 */ +#line 1337 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[-2])->lasti->opcode == Op_match_rec) warning_ln((yyvsp[-1])->source_line, @@ -3196,11 +3261,11 @@ regular_print: (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); } } -#line 3200 "awkgram.c" /* yacc.c:1646 */ +#line 3265 "awkgram.c" /* yacc.c:1646 */ break; case 114: -#line 1287 "awkgram.y" /* yacc.c:1646 */ +#line 1353 "awkgram.y" /* yacc.c:1646 */ { if (do_lint_old) warning_ln((yyvsp[-1])->source_line, @@ -3210,91 +3275,91 @@ regular_print: (yyvsp[-1])->expr_count = 1; (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); } -#line 3214 "awkgram.c" /* yacc.c:1646 */ +#line 3279 "awkgram.c" /* yacc.c:1646 */ break; case 115: -#line 1297 "awkgram.y" /* yacc.c:1646 */ +#line 1363 "awkgram.y" /* yacc.c:1646 */ { if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec) lintwarn_ln((yyvsp[-1])->source_line, _("regular expression on right of comparison")); (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); } -#line 3225 "awkgram.c" /* yacc.c:1646 */ +#line 3290 "awkgram.c" /* yacc.c:1646 */ break; case 116: -#line 1304 "awkgram.y" /* yacc.c:1646 */ +#line 1370 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_condition((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); } -#line 3231 "awkgram.c" /* yacc.c:1646 */ +#line 3296 "awkgram.c" /* yacc.c:1646 */ break; case 117: -#line 1306 "awkgram.y" /* yacc.c:1646 */ +#line 1372 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3237 "awkgram.c" /* yacc.c:1646 */ +#line 3302 "awkgram.c" /* yacc.c:1646 */ break; case 118: -#line 1311 "awkgram.y" /* yacc.c:1646 */ +#line 1377 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3243 "awkgram.c" /* yacc.c:1646 */ +#line 3308 "awkgram.c" /* yacc.c:1646 */ break; case 119: -#line 1313 "awkgram.y" /* yacc.c:1646 */ +#line 1379 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3249 "awkgram.c" /* yacc.c:1646 */ +#line 3314 "awkgram.c" /* yacc.c:1646 */ break; case 120: -#line 1315 "awkgram.y" /* yacc.c:1646 */ +#line 1381 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_assign_quotient; (yyval) = (yyvsp[0]); } -#line 3258 "awkgram.c" /* yacc.c:1646 */ +#line 3323 "awkgram.c" /* yacc.c:1646 */ break; case 121: -#line 1323 "awkgram.y" /* yacc.c:1646 */ +#line 1389 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3264 "awkgram.c" /* yacc.c:1646 */ +#line 3329 "awkgram.c" /* yacc.c:1646 */ break; case 122: -#line 1325 "awkgram.y" /* yacc.c:1646 */ +#line 1391 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3270 "awkgram.c" /* yacc.c:1646 */ +#line 3335 "awkgram.c" /* yacc.c:1646 */ break; case 123: -#line 1330 "awkgram.y" /* yacc.c:1646 */ +#line 1396 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3276 "awkgram.c" /* yacc.c:1646 */ +#line 3341 "awkgram.c" /* yacc.c:1646 */ break; case 124: -#line 1332 "awkgram.y" /* yacc.c:1646 */ +#line 1398 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3282 "awkgram.c" /* yacc.c:1646 */ +#line 3347 "awkgram.c" /* yacc.c:1646 */ break; case 125: -#line 1337 "awkgram.y" /* yacc.c:1646 */ +#line 1403 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3288 "awkgram.c" /* yacc.c:1646 */ +#line 3353 "awkgram.c" /* yacc.c:1646 */ break; case 126: -#line 1339 "awkgram.y" /* yacc.c:1646 */ +#line 1405 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3294 "awkgram.c" /* yacc.c:1646 */ +#line 3359 "awkgram.c" /* yacc.c:1646 */ break; case 127: -#line 1341 "awkgram.y" /* yacc.c:1646 */ +#line 1407 "awkgram.y" /* yacc.c:1646 */ { int count = 2; bool is_simple_var = false; @@ -3341,47 +3406,47 @@ regular_print: max_args = count; } } -#line 3345 "awkgram.c" /* yacc.c:1646 */ +#line 3410 "awkgram.c" /* yacc.c:1646 */ break; case 129: -#line 1393 "awkgram.y" /* yacc.c:1646 */ +#line 1459 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3351 "awkgram.c" /* yacc.c:1646 */ +#line 3416 "awkgram.c" /* yacc.c:1646 */ break; case 130: -#line 1395 "awkgram.y" /* yacc.c:1646 */ +#line 1461 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3357 "awkgram.c" /* yacc.c:1646 */ +#line 3422 "awkgram.c" /* yacc.c:1646 */ break; case 131: -#line 1397 "awkgram.y" /* yacc.c:1646 */ +#line 1463 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3363 "awkgram.c" /* yacc.c:1646 */ +#line 3428 "awkgram.c" /* yacc.c:1646 */ break; case 132: -#line 1399 "awkgram.y" /* yacc.c:1646 */ +#line 1465 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3369 "awkgram.c" /* yacc.c:1646 */ +#line 3434 "awkgram.c" /* yacc.c:1646 */ break; case 133: -#line 1401 "awkgram.y" /* yacc.c:1646 */ +#line 1467 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3375 "awkgram.c" /* yacc.c:1646 */ +#line 3440 "awkgram.c" /* yacc.c:1646 */ break; case 134: -#line 1403 "awkgram.y" /* yacc.c:1646 */ +#line 1469 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3381 "awkgram.c" /* yacc.c:1646 */ +#line 3446 "awkgram.c" /* yacc.c:1646 */ break; case 135: -#line 1405 "awkgram.y" /* yacc.c:1646 */ +#line 1471 "awkgram.y" /* yacc.c:1646 */ { /* * In BEGINFILE/ENDFILE, allow `getline [var] < file' @@ -3395,29 +3460,29 @@ regular_print: _("non-redirected `getline' undefined inside END action")); (yyval) = mk_getline((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), redirect_input); } -#line 3399 "awkgram.c" /* yacc.c:1646 */ +#line 3464 "awkgram.c" /* yacc.c:1646 */ break; case 136: -#line 1419 "awkgram.y" /* yacc.c:1646 */ +#line 1485 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_postincrement; (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 3408 "awkgram.c" /* yacc.c:1646 */ +#line 3473 "awkgram.c" /* yacc.c:1646 */ break; case 137: -#line 1424 "awkgram.y" /* yacc.c:1646 */ +#line 1490 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_postdecrement; (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 3417 "awkgram.c" /* yacc.c:1646 */ +#line 3482 "awkgram.c" /* yacc.c:1646 */ break; case 138: -#line 1429 "awkgram.y" /* yacc.c:1646 */ +#line 1495 "awkgram.y" /* yacc.c:1646 */ { if (do_lint_old) { warning_ln((yyvsp[-1])->source_line, @@ -3437,64 +3502,64 @@ regular_print: (yyval) = list_append(list_merge(t, (yyvsp[0])), (yyvsp[-1])); } } -#line 3441 "awkgram.c" /* yacc.c:1646 */ +#line 3506 "awkgram.c" /* yacc.c:1646 */ break; case 139: -#line 1454 "awkgram.y" /* yacc.c:1646 */ +#line 1520 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_getline((yyvsp[-1]), (yyvsp[0]), (yyvsp[-3]), (yyvsp[-2])->redir_type); bcfree((yyvsp[-2])); } -#line 3450 "awkgram.c" /* yacc.c:1646 */ +#line 3515 "awkgram.c" /* yacc.c:1646 */ break; case 140: -#line 1460 "awkgram.y" /* yacc.c:1646 */ +#line 1526 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3456 "awkgram.c" /* yacc.c:1646 */ +#line 3521 "awkgram.c" /* yacc.c:1646 */ break; case 141: -#line 1462 "awkgram.y" /* yacc.c:1646 */ +#line 1528 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3462 "awkgram.c" /* yacc.c:1646 */ +#line 3527 "awkgram.c" /* yacc.c:1646 */ break; case 142: -#line 1464 "awkgram.y" /* yacc.c:1646 */ +#line 1530 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3468 "awkgram.c" /* yacc.c:1646 */ +#line 3533 "awkgram.c" /* yacc.c:1646 */ break; case 143: -#line 1466 "awkgram.y" /* yacc.c:1646 */ +#line 1532 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3474 "awkgram.c" /* yacc.c:1646 */ +#line 3539 "awkgram.c" /* yacc.c:1646 */ break; case 144: -#line 1468 "awkgram.y" /* yacc.c:1646 */ +#line 1534 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3480 "awkgram.c" /* yacc.c:1646 */ +#line 3545 "awkgram.c" /* yacc.c:1646 */ break; case 145: -#line 1470 "awkgram.y" /* yacc.c:1646 */ +#line 1536 "awkgram.y" /* yacc.c:1646 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3486 "awkgram.c" /* yacc.c:1646 */ +#line 3551 "awkgram.c" /* yacc.c:1646 */ break; case 146: -#line 1475 "awkgram.y" /* yacc.c:1646 */ +#line 1541 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_create((yyvsp[0])); } -#line 3494 "awkgram.c" /* yacc.c:1646 */ +#line 3559 "awkgram.c" /* yacc.c:1646 */ break; case 147: -#line 1479 "awkgram.y" /* yacc.c:1646 */ +#line 1545 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[0])->opcode == Op_match_rec) { (yyvsp[0])->opcode = Op_nomatch; @@ -3526,37 +3591,37 @@ regular_print: } } } -#line 3530 "awkgram.c" /* yacc.c:1646 */ +#line 3595 "awkgram.c" /* yacc.c:1646 */ break; case 148: -#line 1511 "awkgram.y" /* yacc.c:1646 */ +#line 1577 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 3536 "awkgram.c" /* yacc.c:1646 */ +#line 3601 "awkgram.c" /* yacc.c:1646 */ break; case 149: -#line 1513 "awkgram.y" /* yacc.c:1646 */ +#line 1579 "awkgram.y" /* yacc.c:1646 */ { (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); if ((yyval) == NULL) YYABORT; } -#line 3546 "awkgram.c" /* yacc.c:1646 */ +#line 3611 "awkgram.c" /* yacc.c:1646 */ break; case 150: -#line 1519 "awkgram.y" /* yacc.c:1646 */ +#line 1585 "awkgram.y" /* yacc.c:1646 */ { (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); if ((yyval) == NULL) YYABORT; } -#line 3556 "awkgram.c" /* yacc.c:1646 */ +#line 3621 "awkgram.c" /* yacc.c:1646 */ break; case 151: -#line 1525 "awkgram.y" /* yacc.c:1646 */ +#line 1591 "awkgram.y" /* yacc.c:1646 */ { static bool warned = false; @@ -3569,45 +3634,45 @@ regular_print: if ((yyval) == NULL) YYABORT; } -#line 3573 "awkgram.c" /* yacc.c:1646 */ +#line 3638 "awkgram.c" /* yacc.c:1646 */ break; case 154: -#line 1540 "awkgram.y" /* yacc.c:1646 */ +#line 1606 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[-1])->opcode = Op_preincrement; (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); } -#line 3582 "awkgram.c" /* yacc.c:1646 */ +#line 3647 "awkgram.c" /* yacc.c:1646 */ break; case 155: -#line 1545 "awkgram.y" /* yacc.c:1646 */ +#line 1611 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[-1])->opcode = Op_predecrement; (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); } -#line 3591 "awkgram.c" /* yacc.c:1646 */ +#line 3656 "awkgram.c" /* yacc.c:1646 */ break; case 156: -#line 1550 "awkgram.y" /* yacc.c:1646 */ +#line 1616 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_create((yyvsp[0])); } -#line 3599 "awkgram.c" /* yacc.c:1646 */ +#line 3664 "awkgram.c" /* yacc.c:1646 */ break; case 157: -#line 1554 "awkgram.y" /* yacc.c:1646 */ +#line 1620 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_create((yyvsp[0])); } -#line 3607 "awkgram.c" /* yacc.c:1646 */ +#line 3672 "awkgram.c" /* yacc.c:1646 */ break; case 158: -#line 1558 "awkgram.y" /* yacc.c:1646 */ +#line 1624 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[0])->lasti->opcode == Op_push_i && ((yyvsp[0])->lasti->memory->flags & (STRCUR|STRING)) == 0 @@ -3622,11 +3687,11 @@ regular_print: (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); } } -#line 3626 "awkgram.c" /* yacc.c:1646 */ +#line 3691 "awkgram.c" /* yacc.c:1646 */ break; case 159: -#line 1573 "awkgram.y" /* yacc.c:1646 */ +#line 1639 "awkgram.y" /* yacc.c:1646 */ { /* * was: $$ = $2 @@ -3636,20 +3701,20 @@ regular_print: (yyvsp[-1])->memory = make_number(0.0); (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); } -#line 3640 "awkgram.c" /* yacc.c:1646 */ +#line 3705 "awkgram.c" /* yacc.c:1646 */ break; case 160: -#line 1586 "awkgram.y" /* yacc.c:1646 */ +#line 1652 "awkgram.y" /* yacc.c:1646 */ { func_use((yyvsp[0])->lasti->func_name, FUNC_USE); (yyval) = (yyvsp[0]); } -#line 3649 "awkgram.c" /* yacc.c:1646 */ +#line 3714 "awkgram.c" /* yacc.c:1646 */ break; case 161: -#line 1591 "awkgram.y" /* yacc.c:1646 */ +#line 1657 "awkgram.y" /* yacc.c:1646 */ { /* indirect function call */ INSTRUCTION *f, *t; @@ -3682,11 +3747,11 @@ regular_print: (yyval) = list_prepend((yyvsp[0]), t); } -#line 3686 "awkgram.c" /* yacc.c:1646 */ +#line 3751 "awkgram.c" /* yacc.c:1646 */ break; case 162: -#line 1627 "awkgram.y" /* yacc.c:1646 */ +#line 1693 "awkgram.y" /* yacc.c:1646 */ { param_sanity((yyvsp[-1])); (yyvsp[-3])->opcode = Op_func_call; @@ -3700,49 +3765,49 @@ regular_print: (yyval) = list_append(t, (yyvsp[-3])); } } -#line 3704 "awkgram.c" /* yacc.c:1646 */ +#line 3769 "awkgram.c" /* yacc.c:1646 */ break; case 163: -#line 1644 "awkgram.y" /* yacc.c:1646 */ +#line 1710 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3710 "awkgram.c" /* yacc.c:1646 */ +#line 3775 "awkgram.c" /* yacc.c:1646 */ break; case 164: -#line 1646 "awkgram.y" /* yacc.c:1646 */ +#line 1712 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3716 "awkgram.c" /* yacc.c:1646 */ +#line 3781 "awkgram.c" /* yacc.c:1646 */ break; case 165: -#line 1651 "awkgram.y" /* yacc.c:1646 */ +#line 1717 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3722 "awkgram.c" /* yacc.c:1646 */ +#line 3787 "awkgram.c" /* yacc.c:1646 */ break; case 166: -#line 1653 "awkgram.y" /* yacc.c:1646 */ +#line 1719 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 3728 "awkgram.c" /* yacc.c:1646 */ +#line 3793 "awkgram.c" /* yacc.c:1646 */ break; case 167: -#line 1658 "awkgram.y" /* yacc.c:1646 */ +#line 1724 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3734 "awkgram.c" /* yacc.c:1646 */ +#line 3799 "awkgram.c" /* yacc.c:1646 */ break; case 168: -#line 1660 "awkgram.y" /* yacc.c:1646 */ +#line 1726 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); } -#line 3742 "awkgram.c" /* yacc.c:1646 */ +#line 3807 "awkgram.c" /* yacc.c:1646 */ break; case 169: -#line 1667 "awkgram.y" /* yacc.c:1646 */ +#line 1733 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *ip = (yyvsp[0])->lasti; int count = ip->sub_count; /* # of SUBSEP-seperated expressions */ @@ -3756,11 +3821,11 @@ regular_print: sub_counter++; /* count # of dimensions */ (yyval) = (yyvsp[0]); } -#line 3760 "awkgram.c" /* yacc.c:1646 */ +#line 3825 "awkgram.c" /* yacc.c:1646 */ break; case 170: -#line 1684 "awkgram.y" /* yacc.c:1646 */ +#line 1750 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *t = (yyvsp[-1]); if ((yyvsp[-1]) == NULL) { @@ -3774,31 +3839,31 @@ regular_print: (yyvsp[0])->sub_count = count_expressions(&t, false); (yyval) = list_append(t, (yyvsp[0])); } -#line 3778 "awkgram.c" /* yacc.c:1646 */ +#line 3843 "awkgram.c" /* yacc.c:1646 */ break; case 171: -#line 1701 "awkgram.y" /* yacc.c:1646 */ +#line 1767 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); } -#line 3784 "awkgram.c" /* yacc.c:1646 */ +#line 3849 "awkgram.c" /* yacc.c:1646 */ break; case 172: -#line 1703 "awkgram.y" /* yacc.c:1646 */ +#line 1769 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); } -#line 3792 "awkgram.c" /* yacc.c:1646 */ +#line 3857 "awkgram.c" /* yacc.c:1646 */ break; case 173: -#line 1710 "awkgram.y" /* yacc.c:1646 */ +#line 1776 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[-1]); } -#line 3798 "awkgram.c" /* yacc.c:1646 */ +#line 3863 "awkgram.c" /* yacc.c:1646 */ break; case 174: -#line 1715 "awkgram.y" /* yacc.c:1646 */ +#line 1781 "awkgram.y" /* yacc.c:1646 */ { char *var_name = (yyvsp[0])->lextok; @@ -3806,22 +3871,22 @@ regular_print: (yyvsp[0])->memory = variable((yyvsp[0])->source_line, var_name, Node_var_new); (yyval) = list_create((yyvsp[0])); } -#line 3810 "awkgram.c" /* yacc.c:1646 */ +#line 3875 "awkgram.c" /* yacc.c:1646 */ break; case 175: -#line 1723 "awkgram.y" /* yacc.c:1646 */ +#line 1789 "awkgram.y" /* yacc.c:1646 */ { char *arr = (yyvsp[-1])->lextok; (yyvsp[-1])->memory = variable((yyvsp[-1])->source_line, arr, Node_var_new); (yyvsp[-1])->opcode = Op_push_array; (yyval) = list_prepend((yyvsp[0]), (yyvsp[-1])); } -#line 3821 "awkgram.c" /* yacc.c:1646 */ +#line 3886 "awkgram.c" /* yacc.c:1646 */ break; case 176: -#line 1733 "awkgram.y" /* yacc.c:1646 */ +#line 1799 "awkgram.y" /* yacc.c:1646 */ { INSTRUCTION *ip = (yyvsp[0])->nexti; if (ip->opcode == Op_push @@ -3833,73 +3898,73 @@ regular_print: } else (yyval) = (yyvsp[0]); } -#line 3837 "awkgram.c" /* yacc.c:1646 */ +#line 3902 "awkgram.c" /* yacc.c:1646 */ break; case 177: -#line 1745 "awkgram.y" /* yacc.c:1646 */ +#line 1811 "awkgram.y" /* yacc.c:1646 */ { (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); if ((yyvsp[0]) != NULL) mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 3847 "awkgram.c" /* yacc.c:1646 */ +#line 3912 "awkgram.c" /* yacc.c:1646 */ break; case 178: -#line 1754 "awkgram.y" /* yacc.c:1646 */ +#line 1820 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_postincrement; } -#line 3855 "awkgram.c" /* yacc.c:1646 */ +#line 3920 "awkgram.c" /* yacc.c:1646 */ break; case 179: -#line 1758 "awkgram.y" /* yacc.c:1646 */ +#line 1824 "awkgram.y" /* yacc.c:1646 */ { (yyvsp[0])->opcode = Op_postdecrement; } -#line 3863 "awkgram.c" /* yacc.c:1646 */ +#line 3928 "awkgram.c" /* yacc.c:1646 */ break; case 180: -#line 1761 "awkgram.y" /* yacc.c:1646 */ +#line 1827 "awkgram.y" /* yacc.c:1646 */ { (yyval) = NULL; } -#line 3869 "awkgram.c" /* yacc.c:1646 */ +#line 3934 "awkgram.c" /* yacc.c:1646 */ break; case 182: -#line 1769 "awkgram.y" /* yacc.c:1646 */ +#line 1835 "awkgram.y" /* yacc.c:1646 */ { yyerrok; } -#line 3875 "awkgram.c" /* yacc.c:1646 */ +#line 3940 "awkgram.c" /* yacc.c:1646 */ break; case 183: -#line 1773 "awkgram.y" /* yacc.c:1646 */ +#line 1839 "awkgram.y" /* yacc.c:1646 */ { yyerrok; } -#line 3881 "awkgram.c" /* yacc.c:1646 */ +#line 3946 "awkgram.c" /* yacc.c:1646 */ break; case 186: -#line 1782 "awkgram.y" /* yacc.c:1646 */ +#line 1848 "awkgram.y" /* yacc.c:1646 */ { yyerrok; } -#line 3887 "awkgram.c" /* yacc.c:1646 */ +#line 3952 "awkgram.c" /* yacc.c:1646 */ break; case 187: -#line 1786 "awkgram.y" /* yacc.c:1646 */ +#line 1852 "awkgram.y" /* yacc.c:1646 */ { (yyval) = (yyvsp[0]); yyerrok; } -#line 3893 "awkgram.c" /* yacc.c:1646 */ +#line 3958 "awkgram.c" /* yacc.c:1646 */ break; case 188: -#line 1790 "awkgram.y" /* yacc.c:1646 */ +#line 1856 "awkgram.y" /* yacc.c:1646 */ { yyerrok; } -#line 3899 "awkgram.c" /* yacc.c:1646 */ +#line 3964 "awkgram.c" /* yacc.c:1646 */ break; -#line 3903 "awkgram.c" /* yacc.c:1646 */ +#line 3968 "awkgram.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -4127,7 +4192,7 @@ yyreturn: #endif return yyresult; } -#line 1792 "awkgram.y" /* yacc.c:1906 */ +#line 1858 "awkgram.y" /* yacc.c:1906 */ struct token { @@ -4561,6 +4626,13 @@ mk_program() cp = end_block; else cp = list_merge(begin_block, end_block); + /* + * We don't need to clear the comment variables + * since they're not used anymore after this + * function is called. + */ + if (comment != NULL) + (void) list_append(cp, comment); (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -4593,6 +4665,12 @@ mk_program() if (begin_block != NULL) cp = list_merge(begin_block, cp); + if (program_comment != NULL) { + (void) list_prepend(cp, program_comment); + } + if (comment != NULL) { + (void) list_append(cp, comment); + } (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -5094,7 +5172,7 @@ get_src_buf() lexend = lexptr + n; if (n == 0) { static bool warned = false; - if (do_lint && newfile && ! warned){ + if (do_lint && newfile && ! warned) { warned = true; sourceline = 0; lintwarn(_("source file `%s' is empty"), source); @@ -5156,7 +5234,7 @@ check_bad_char(int c) } if (iscntrl(c) && ! isspace(c)) - fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c); + fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c & 0xFF); } /* nextc --- get the next input character */ @@ -5187,7 +5265,7 @@ again: mbstate_t tmp_state; size_t mbclen; - for (idx = 0 ; lexptr + idx < lexend ; idx++) { + for (idx = 0; lexptr + idx < lexend; idx++) { tmp_state = cur_mbstate; mbclen = mbrlen(lexptr, idx + 1, &tmp_state); @@ -5266,6 +5344,79 @@ pushback(void) } +/* get_comment --- collect comment text */ + +int +get_comment(void) +{ + int c; + int sl; + tok = tokstart; + tokadd('#'); + sl = sourceline; + + while (true) { + while ((c = nextc(false)) != '\n' && c != END_FILE) { + tokadd(c); + } + if (c == '\n') { + tokadd(c); + sourceline++; + do { + c = nextc(false); + if (c == '\n') { + sourceline++; + tokadd(c); + } + } while (isspace(c) && c != END_FILE); + if (c == END_FILE) + break; + else if (c != '#') { + pushback(); + break; + } else + tokadd(c); + } else + break; + } + comment = bcalloc(Op_comment, 1, sl); + comment->source_file = source; + comment->memory = make_str_node(tokstart, tok - tokstart, 0); + + return c; +} + +/* split_comment --- split initial comment text into program and function parts */ + +static void +split_comment(void) +{ + char *p; + int l; + NODE *n; + + p = comment->memory->stptr; + l = comment->memory->stlen - 3; + /* have at least two comments so split at last blank line (\n\n) */ + while (l >= 0) { + if (p[l] == '\n' && p[l+1] == '\n') { + function_comment = comment; + n = function_comment->memory; + function_comment->memory = make_str_node(p + l + 2, n->stlen - l - 2, 0); + /* create program comment */ + program_comment = bcalloc(Op_comment, 1, sourceline); + program_comment->source_file = comment->source_file; + p[l + 2] = 0; + program_comment->memory = make_str_node(p, l + 2, 0); + comment = NULL; + freenode(n); + break; + } + else + l--; + } +} + /* allow_newline --- allow newline after &&, ||, ? and : */ static void @@ -5280,8 +5431,13 @@ allow_newline(void) break; } if (c == '#') { - while ((c = nextc(false)) != '\n' && c != END_FILE) - continue; + if (do_pretty_print && ! do_profile) { + /* collect comment byte code iff doing pretty print but not profiling. */ + c = get_comment(); + } else { + while ((c = nextc(false)) != '\n' && c != END_FILE) + continue; + } if (c == END_FILE) { pushback(); break; @@ -5304,7 +5460,8 @@ allow_newline(void) * removes the warnings. */ -static int newline_eof() +static int +newline_eof() { /* NB: a newline at end does not start a source line. */ if (lasttok != NEWLINE) { @@ -5485,9 +5642,20 @@ retry: return lasttok = NEWLINE; case '#': /* it's a comment */ - while ((c = nextc(false)) != '\n') { + if (do_pretty_print && ! do_profile) { + /* + * Collect comment byte code iff doing pretty print + * but not profiling. + */ + c = get_comment(); + if (c == END_FILE) return lasttok = NEWLINE_EOF; + } else { + while ((c = nextc(false)) != '\n') { + if (c == END_FILE) + return lasttok = NEWLINE_EOF; + } } sourceline++; return lasttok = NEWLINE; @@ -5498,7 +5666,7 @@ retry: case '\\': #ifdef RELAXED_CONTINUATION /* - * This code puports to allow comments and/or whitespace + * This code purports to allow comments and/or whitespace * after the `\' at the end of a line used for continuation. * Use it at your own risk. We think it's a bad idea, which * is why it's not on by default. @@ -5515,9 +5683,13 @@ retry: lintwarn( _("use of `\\ #...' line continuation is not portable")); } - while ((c = nextc(false)) != '\n') - if (c == END_FILE) - break; + if (do_pretty_print && ! do_profile) + c = get_comment(); + else { + while ((c = nextc(false)) != '\n') + if (c == END_FILE) + break; + } } pushback(); } @@ -5729,14 +5901,18 @@ retry: lastline = sourceline; return lasttok = c; } - did_newline++; + did_newline = true; --lexptr; /* pick up } next time */ return lasttok = NEWLINE; case '"': string: esc_seen = false; - while ((c = nextc(true)) != '"') { + /* + * Allow any kind of junk in quoted string, + * so pass false to nextc(). + */ + while ((c = nextc(false)) != '"') { if (c == '\n') { pushback(); yyerror(_("unterminated string")); @@ -6578,6 +6754,14 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) (t + 1)->tail_call = true; } + /* add any pre-function comment to start of action for profile.c */ + + if (function_comment != NULL) { + function_comment->source_line = 0; + (void) list_prepend(def, function_comment); + function_comment = NULL; + } + /* add an implicit return at end; * also used by 'return' command in debugger */ @@ -7397,7 +7581,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) action), tp); } - } list_append(rule_list, rp + 1); @@ -87,6 +87,7 @@ static void check_funcs(void); static ssize_t read_one_line(int fd, void *buffer, size_t count); static int one_line_close(int fd); +static void split_comment(void); static bool want_source = false; static bool want_regexp = false; /* lexical scanning kludge */ @@ -147,6 +148,12 @@ static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; INSTRUCTION *main_beginfile; +static INSTRUCTION *comment = NULL; +static INSTRUCTION *program_comment = NULL; +static INSTRUCTION *function_comment = NULL; + +static bool func_first = true; + static inline INSTRUCTION *list_create(INSTRUCTION *x); static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x); static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x); @@ -287,9 +294,24 @@ library pattern : /* empty */ - { $$ = NULL; rule = Rule; } + { + rule = Rule; + if (comment != NULL) { + $$ = list_create(comment); + comment = NULL; + } else + $$ = NULL; + } | exp - { $$ = $1; rule = Rule; } + { + rule = Rule; + if (comment != NULL) { + $$ = list_prepend($1, comment); + comment = NULL; + } else + $$ = $1; + } + | exp ',' opt_nls exp { INSTRUCTION *tp; @@ -319,6 +341,8 @@ pattern | LEX_BEGIN { static int begin_seen = 0; + + func_first = false; if (do_lint_old && ++begin_seen == 2) warning_ln($1->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -330,6 +354,8 @@ pattern | LEX_END { static int end_seen = 0; + + func_first = false; if (do_lint_old && ++end_seen == 2) warning_ln($1->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -340,12 +366,14 @@ pattern } | LEX_BEGINFILE { + func_first = false; $1->in_rule = rule = BEGINFILE; $1->source_file = source; $$ = $1; } | LEX_ENDFILE { + func_first = false; $1->in_rule = rule = ENDFILE; $1->source_file = source; $$ = $1; @@ -355,10 +383,12 @@ pattern action : l_brace statements r_brace opt_semi opt_nls { + INSTRUCTION *ip; if ($2 == NULL) - $$ = list_create(instruction(Op_no_op)); + ip = list_create(instruction(Op_no_op)); else - $$ = $2; + ip = $2; + $$ = ip; } ; @@ -385,6 +415,22 @@ lex_builtin function_prologue : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls { + /* + * treat any comments between BOF and the first function + * definition (with no intervening BEGIN etc block) as + * program comments. Special kludge: iff there are more + * than one such comments, treat the last as a function + * comment. + */ + if (comment != NULL && func_first + && strstr(comment->memory->stptr, "\n\n") != NULL) + split_comment(); + /* save any other pre-function comment as function comment */ + if (comment != NULL) { + function_comment = comment; + comment = NULL; + } + func_first = false; $1->source_file = source; if (install_function($2->lextok, $1, $4) < 0) YYABORT; @@ -442,19 +488,39 @@ a_slash statements : /* empty */ - { $$ = NULL; } + { + if (comment != NULL) { + $$ = list_create(comment); + comment = NULL; + } else $$ = NULL; + } | statements statement { - if ($2 == NULL) - $$ = $1; - else { + if ($2 == NULL) { + if (comment == NULL) + $$ = $1; + else { + $$ = list_append($1, comment); + comment = NULL; + } + } else { add_lint($2, LINT_no_effect); - if ($1 == NULL) - $$ = $2; - else + if ($1 == NULL) { + if (comment == NULL) + $$ = $2; + else { + $$ = list_append($2, comment); + comment = NULL; + } + } else { + if (comment != NULL) { + list_append($2, comment); + comment = NULL; + } $$ = list_merge($1, $2); + } } - yyerrok; + yyerrok; } | statements error { $$ = NULL; } @@ -498,7 +564,7 @@ statement } /* else curr = NULL; */ - for(; curr != NULL; curr = nextc) { + for (; curr != NULL; curr = nextc) { INSTRUCTION *caseexp = curr->case_exp; INSTRUCTION *casestmt = curr->case_stmt; @@ -1186,7 +1252,7 @@ opt_param_list : /* empty */ { $$ = NULL; } | param_list - { $$ = $1 ; } + { $$ = $1; } ; param_list @@ -2222,6 +2288,13 @@ mk_program() cp = end_block; else cp = list_merge(begin_block, end_block); + /* + * We don't need to clear the comment variables + * since they're not used anymore after this + * function is called. + */ + if (comment != NULL) + (void) list_append(cp, comment); (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2254,6 +2327,12 @@ mk_program() if (begin_block != NULL) cp = list_merge(begin_block, cp); + if (program_comment != NULL) { + (void) list_prepend(cp, program_comment); + } + if (comment != NULL) { + (void) list_append(cp, comment); + } (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2755,7 +2834,7 @@ get_src_buf() lexend = lexptr + n; if (n == 0) { static bool warned = false; - if (do_lint && newfile && ! warned){ + if (do_lint && newfile && ! warned) { warned = true; sourceline = 0; lintwarn(_("source file `%s' is empty"), source); @@ -2817,7 +2896,7 @@ check_bad_char(int c) } if (iscntrl(c) && ! isspace(c)) - fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c); + fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c & 0xFF); } /* nextc --- get the next input character */ @@ -2848,7 +2927,7 @@ again: mbstate_t tmp_state; size_t mbclen; - for (idx = 0 ; lexptr + idx < lexend ; idx++) { + for (idx = 0; lexptr + idx < lexend; idx++) { tmp_state = cur_mbstate; mbclen = mbrlen(lexptr, idx + 1, &tmp_state); @@ -2927,6 +3006,79 @@ pushback(void) } +/* get_comment --- collect comment text */ + +int +get_comment(void) +{ + int c; + int sl; + tok = tokstart; + tokadd('#'); + sl = sourceline; + + while (true) { + while ((c = nextc(false)) != '\n' && c != END_FILE) { + tokadd(c); + } + if (c == '\n') { + tokadd(c); + sourceline++; + do { + c = nextc(false); + if (c == '\n') { + sourceline++; + tokadd(c); + } + } while (isspace(c) && c != END_FILE); + if (c == END_FILE) + break; + else if (c != '#') { + pushback(); + break; + } else + tokadd(c); + } else + break; + } + comment = bcalloc(Op_comment, 1, sl); + comment->source_file = source; + comment->memory = make_str_node(tokstart, tok - tokstart, 0); + + return c; +} + +/* split_comment --- split initial comment text into program and function parts */ + +static void +split_comment(void) +{ + char *p; + int l; + NODE *n; + + p = comment->memory->stptr; + l = comment->memory->stlen - 3; + /* have at least two comments so split at last blank line (\n\n) */ + while (l >= 0) { + if (p[l] == '\n' && p[l+1] == '\n') { + function_comment = comment; + n = function_comment->memory; + function_comment->memory = make_str_node(p + l + 2, n->stlen - l - 2, 0); + /* create program comment */ + program_comment = bcalloc(Op_comment, 1, sourceline); + program_comment->source_file = comment->source_file; + p[l + 2] = 0; + program_comment->memory = make_str_node(p, l + 2, 0); + comment = NULL; + freenode(n); + break; + } + else + l--; + } +} + /* allow_newline --- allow newline after &&, ||, ? and : */ static void @@ -2941,8 +3093,13 @@ allow_newline(void) break; } if (c == '#') { - while ((c = nextc(false)) != '\n' && c != END_FILE) - continue; + if (do_pretty_print && ! do_profile) { + /* collect comment byte code iff doing pretty print but not profiling. */ + c = get_comment(); + } else { + while ((c = nextc(false)) != '\n' && c != END_FILE) + continue; + } if (c == END_FILE) { pushback(); break; @@ -2965,7 +3122,8 @@ allow_newline(void) * removes the warnings. */ -static int newline_eof() +static int +newline_eof() { /* NB: a newline at end does not start a source line. */ if (lasttok != NEWLINE) { @@ -3146,9 +3304,20 @@ retry: return lasttok = NEWLINE; case '#': /* it's a comment */ - while ((c = nextc(false)) != '\n') { + if (do_pretty_print && ! do_profile) { + /* + * Collect comment byte code iff doing pretty print + * but not profiling. + */ + c = get_comment(); + if (c == END_FILE) return lasttok = NEWLINE_EOF; + } else { + while ((c = nextc(false)) != '\n') { + if (c == END_FILE) + return lasttok = NEWLINE_EOF; + } } sourceline++; return lasttok = NEWLINE; @@ -3159,7 +3328,7 @@ retry: case '\\': #ifdef RELAXED_CONTINUATION /* - * This code puports to allow comments and/or whitespace + * This code purports to allow comments and/or whitespace * after the `\' at the end of a line used for continuation. * Use it at your own risk. We think it's a bad idea, which * is why it's not on by default. @@ -3176,9 +3345,13 @@ retry: lintwarn( _("use of `\\ #...' line continuation is not portable")); } - while ((c = nextc(false)) != '\n') - if (c == END_FILE) - break; + if (do_pretty_print && ! do_profile) + c = get_comment(); + else { + while ((c = nextc(false)) != '\n') + if (c == END_FILE) + break; + } } pushback(); } @@ -3390,14 +3563,18 @@ retry: lastline = sourceline; return lasttok = c; } - did_newline++; + did_newline = true; --lexptr; /* pick up } next time */ return lasttok = NEWLINE; case '"': string: esc_seen = false; - while ((c = nextc(true)) != '"') { + /* + * Allow any kind of junk in quoted string, + * so pass false to nextc(). + */ + while ((c = nextc(false)) != '"') { if (c == '\n') { pushback(); yyerror(_("unterminated string")); @@ -4239,6 +4416,14 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) (t + 1)->tail_call = true; } + /* add any pre-function comment to start of action for profile.c */ + + if (function_comment != NULL) { + function_comment->source_line = 0; + (void) list_prepend(def, function_comment); + function_comment = NULL; + } + /* add an implicit return at end; * also used by 'return' command in debugger */ @@ -5058,7 +5243,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) action), tp); } - } list_append(rule_list, rp + 1); diff --git a/awklib/ChangeLog b/awklib/ChangeLog index 6ef0bbde..13d6b090 100644 --- a/awklib/ChangeLog +++ b/awklib/ChangeLog @@ -1,3 +1,8 @@ +2014-10-17 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (stamp-eg): Use explicit ./extract.awk to avoid + assumptions about AWKPATH in the environment. + 2014-04-08 Arnold D. Robbins <arnold@skeeve.com> * 4.1.1: Release tar ball made. diff --git a/awklib/Makefile.am b/awklib/Makefile.am index 87ee96b8..c1d58780 100644 --- a/awklib/Makefile.am +++ b/awklib/Makefile.am @@ -66,7 +66,7 @@ $(srcdir)/stamp-eg: $(srcdir)/../doc/gawk.texi $(srcdir)/../doc/gawkinet.texi cd $(srcdir) && \ rm -fr eg && \ rm -fr stamp-eg && \ - $(AWKPROG) -f extract.awk ../doc/gawk.texi ../doc/gawkinet.texi + $(AWKPROG) -f ./extract.awk ../doc/gawk.texi ../doc/gawkinet.texi @echo 'some makes are stupid and will not check a directory' > $(srcdir)/stamp-eg @echo 'against a file, so this file is a place holder. gack.' >> $(srcdir)/stamp-eg diff --git a/awklib/Makefile.in b/awklib/Makefile.in index 38124fad..cb8097bf 100644 --- a/awklib/Makefile.in +++ b/awklib/Makefile.in @@ -653,7 +653,7 @@ $(srcdir)/stamp-eg: $(srcdir)/../doc/gawk.texi $(srcdir)/../doc/gawkinet.texi cd $(srcdir) && \ rm -fr eg && \ rm -fr stamp-eg && \ - $(AWKPROG) -f extract.awk ../doc/gawk.texi ../doc/gawkinet.texi + $(AWKPROG) -f ./extract.awk ../doc/gawk.texi ../doc/gawkinet.texi @echo 'some makes are stupid and will not check a directory' > $(srcdir)/stamp-eg @echo 'against a file, so this file is a place holder. gack.' >> $(srcdir)/stamp-eg diff --git a/awklib/eg/lib/ctime.awk b/awklib/eg/lib/ctime.awk index ca750370..cea25b7a 100644 --- a/awklib/eg/lib/ctime.awk +++ b/awklib/eg/lib/ctime.awk @@ -4,7 +4,8 @@ function ctime(ts, format) { - format = PROCINFO["strftime"] + format = "%a %b %e %H:%M:%S %Z %Y" + if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) diff --git a/awklib/eg/lib/div.awk b/awklib/eg/lib/div.awk index 9d919288..5939024d 100644 --- a/awklib/eg/lib/div.awk +++ b/awklib/eg/lib/div.awk @@ -4,7 +4,7 @@ # Arnold Robbins, arnold@skeeve.com, Public Domain # July, 2014 -function div(numerator, denominator, result, i) +function div(numerator, denominator, result) { split("", result) diff --git a/awklib/eg/lib/ftrans.awk b/awklib/eg/lib/ftrans.awk index 1709ac82..2fec27ef 100644 --- a/awklib/eg/lib/ftrans.awk +++ b/awklib/eg/lib/ftrans.awk @@ -12,4 +12,4 @@ FNR == 1 { beginfile(FILENAME) } -END { endfile(_filename_) } +END { endfile(_filename_) } diff --git a/awklib/eg/lib/gettime.awk b/awklib/eg/lib/gettime.awk index 3da9c8ab..4cb56330 100644 --- a/awklib/eg/lib/gettime.awk +++ b/awklib/eg/lib/gettime.awk @@ -31,7 +31,7 @@ function getlocaltime(time, ret, now, i) now = systime() # return date(1)-style output - ret = strftime(PROCINFO["strftime"], now) + ret = strftime("%a %b %e %H:%M:%S %Z %Y", now) # clear out target array delete time diff --git a/awklib/eg/lib/groupawk.in b/awklib/eg/lib/groupawk.in index 9382bce8..54a27f3d 100644 --- a/awklib/eg/lib/groupawk.in +++ b/awklib/eg/lib/groupawk.in @@ -38,8 +38,7 @@ function _gr_init( oldfs, oldrs, olddol0, grcat, n = split($4, a, "[ \t]*,[ \t]*") for (i = 1; i <= n; i++) if (a[i] in _gr_groupsbyuser) - _gr_groupsbyuser[a[i]] = \ - _gr_groupsbyuser[a[i]] " " $1 + _gr_groupsbyuser[a[i]] = gr_groupsbyuser[a[i]] " " $1 else _gr_groupsbyuser[a[i]] = $1 diff --git a/awklib/eg/lib/noassign.awk b/awklib/eg/lib/noassign.awk index 1f750edf..99227b37 100644 --- a/awklib/eg/lib/noassign.awk +++ b/awklib/eg/lib/noassign.awk @@ -7,7 +7,7 @@ function disable_assigns(argc, argv, i) { for (i = 1; i < argc; i++) - if (argv[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/) + if (argv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/) argv[i] = ("./" argv[i]) } diff --git a/awklib/eg/lib/processarray.awk b/awklib/eg/lib/processarray.awk new file mode 100644 index 00000000..79a86d1f --- /dev/null +++ b/awklib/eg/lib/processarray.awk @@ -0,0 +1,12 @@ +function process_array(arr, name, process, do_arrays, i, new_name) +{ + for (i in arr) { + new_name = (name "[" i "]") + if (isarray(arr[i])) { + if (do_arrays) + @process(new_name, arr[i]) + process_array(arr[i], new_name, process, do_arrays) + } else + @process(new_name, arr[i]) + } +} diff --git a/awklib/eg/lib/quicksort.awk b/awklib/eg/lib/quicksort.awk index 43357ac6..3ba2d6e3 100644 --- a/awklib/eg/lib/quicksort.awk +++ b/awklib/eg/lib/quicksort.awk @@ -26,7 +26,7 @@ function quicksort(data, left, right, less_than, i, last) # quicksort_swap --- helper function for quicksort, should really be inline -function quicksort_swap(data, i, j, temp) +function quicksort_swap(data, i, j, temp) { temp = data[i] data[i] = data[j] diff --git a/awklib/eg/lib/readable.awk b/awklib/eg/lib/readable.awk index 6942dcca..37970a82 100644 --- a/awklib/eg/lib/readable.awk +++ b/awklib/eg/lib/readable.awk @@ -6,7 +6,7 @@ BEGIN { for (i = 1; i < ARGC; i++) { - if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/ \ + if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \ || ARGV[i] == "-" || ARGV[i] == "/dev/stdin") continue # assignment or standard input else if ((getline junk < ARGV[i]) < 0) # unreadable diff --git a/awklib/eg/lib/shellquote.awk b/awklib/eg/lib/shellquote.awk new file mode 100644 index 00000000..cd943dc7 --- /dev/null +++ b/awklib/eg/lib/shellquote.awk @@ -0,0 +1,22 @@ +# shell_quote --- quote an argument for passing to the shell +# +# Michael Brennan +# brennan@madronabluff.com +# September 2014 + +function shell_quote(s, # parameter + SINGLE, QSINGLE, i, X, n, ret) # locals +{ + if (s == "") + return "\"\"" + + SINGLE = "\x27" # single quote + QSINGLE = "\"\x27\"" + n = split(s, X, SINGLE) + + ret = SINGLE X[1] SINGLE + for (i = 2; i <= n; i++) + ret = ret QSINGLE SINGLE X[i] SINGLE + + return ret +} diff --git a/awklib/eg/lib/strtonum.awk b/awklib/eg/lib/strtonum.awk index f82c89c5..cd56a449 100644 --- a/awklib/eg/lib/strtonum.awk +++ b/awklib/eg/lib/strtonum.awk @@ -51,7 +51,7 @@ function mystrtonum(str, ret, n, i, k, c) # a[5] = "123.45" # a[6] = "1.e3" # a[7] = "1.32" -# a[7] = "1.32E2" +# a[8] = "1.32E2" # # for (i = 1; i in a; i++) # print a[i], strtonum(a[i]), mystrtonum(a[i]) diff --git a/awklib/eg/misc/arraymax.awk b/awklib/eg/misc/arraymax.awk index 20dd1768..64197f56 100644 --- a/awklib/eg/misc/arraymax.awk +++ b/awklib/eg/misc/arraymax.awk @@ -1,10 +1,10 @@ { - if ($1 > max) - max = $1 - arr[$1] = $0 + if ($1 > max) + max = $1 + arr[$1] = $0 } END { - for (x = 1; x <= max; x++) - print arr[x] + for (x = 1; x <= max; x++) + print arr[x] } diff --git a/awklib/eg/misc/findpat.awk b/awklib/eg/misc/findpat.awk index e9bef9ea..9d799434 100644 --- a/awklib/eg/misc/findpat.awk +++ b/awklib/eg/misc/findpat.awk @@ -1,10 +1,9 @@ { - if ($1 == "FIND") - regex = $2 - else { - where = match($0, regex) - if (where != 0) - print "Match of", regex, "found at", - where, "in", $0 + if ($1 == "FIND") + regex = $2 + else { + where = match($0, regex) + if (where != 0) + print "Match of", regex, "found at", where, "in", $0 } } diff --git a/awklib/eg/prog/cut.awk b/awklib/eg/prog/cut.awk index 56e35e71..080279bc 100644 --- a/awklib/eg/prog/cut.awk +++ b/awklib/eg/prog/cut.awk @@ -12,12 +12,10 @@ # # Requires getopt() and join() library functions -function usage( e1, e2) +function usage() { - e1 = "usage: cut [-f list] [-d c] [-s] [files...]" - e2 = "usage: cut [-c list] [files...]" - print e1 > "/dev/stderr" - print e2 > "/dev/stderr" + print("usage: cut [-f list] [-d c] [-s] [files...]") > "/dev/stderr" + print("usage: cut [-c list] [files...]") > "/dev/stderr" exit 1 } BEGIN { diff --git a/awklib/eg/prog/egrep.awk b/awklib/eg/prog/egrep.awk index 094bdea5..a4165a90 100644 --- a/awklib/eg/prog/egrep.awk +++ b/awklib/eg/prog/egrep.awk @@ -91,10 +91,9 @@ function endfile(file) END { exit (total == 0) } -function usage( e) +function usage() { - e = "Usage: egrep [-csvil] [-e pat] [files ...]" - e = e "\n\tegrep [-csvil] pat [files ...]" - print e > "/dev/stderr" + print("Usage: egrep [-csvil] [-e pat] [files ...]") > "/dev/stderr" + print("\n\tegrep [-csvil] pat [files ...]") > "/dev/stderr" exit 1 } diff --git a/awklib/eg/prog/extract.awk b/awklib/eg/prog/extract.awk index 12e30b54..24f40ce5 100644 --- a/awklib/eg/prog/extract.awk +++ b/awklib/eg/prog/extract.awk @@ -1,5 +1,4 @@ -# extract.awk --- extract files and run programs -# from texinfo files +# extract.awk --- extract files and run programs from texinfo files # # Arnold Robbins, arnold@skeeve.com, Public Domain # May 1993 @@ -7,8 +6,7 @@ BEGIN { IGNORECASE = 1 } -/^@c(omment)?[ \t]+system/ \ -{ +/^@c(omment)?[ \t]+system/ { if (NF < 3) { e = ("extract: " FILENAME ":" FNR) e = (e ": badly formed `system' line") @@ -24,8 +22,7 @@ BEGIN { IGNORECASE = 1 } print e > "/dev/stderr" } } -/^@c(omment)?[ \t]+file/ \ -{ +/^@c(omment)?[ \t]+file/ { if (NF != 3) { e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") print e > "/dev/stderr" @@ -66,7 +63,7 @@ BEGIN { IGNORECASE = 1 } function unexpected_eof() { printf("extract: %s:%d: unexpected EOF or error\n", - FILENAME, FNR) > "/dev/stderr" + FILENAME, FNR) > "/dev/stderr" exit 1 } diff --git a/awklib/eg/prog/id.awk b/awklib/eg/prog/id.awk index 992fa57c..b6061f9b 100644 --- a/awklib/eg/prog/id.awk +++ b/awklib/eg/prog/id.awk @@ -6,6 +6,7 @@ # May 1993 # Revised February 1996 # Revised May 2014 +# Revised September 2014 # output is: # uid=12(foo) euid=34(bar) gid=3(baz) \ @@ -19,26 +20,22 @@ BEGIN { printf("uid=%d", uid) pw = getpwuid(uid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (euid != uid) { printf(" euid=%d", euid) pw = getpwuid(euid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) } printf(" gid=%d", gid) pw = getgrgid(gid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (egid != gid) { printf(" egid=%d", egid) pw = getgrgid(egid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) } for (i = 1; ("group" i) in PROCINFO; i++) { @@ -47,8 +44,7 @@ BEGIN { group = PROCINFO["group" i] printf("%d", group) pw = getgrgid(group) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (("group" (i+1)) in PROCINFO) printf(",") } @@ -58,6 +54,8 @@ BEGIN { function pr_first_field(str, a) { - split(str, a, ":") - printf("(%s)", a[1]) + if (str != "") { + split(str, a, ":") + printf("(%s)", a[1]) + } } diff --git a/awklib/eg/prog/pi.awk b/awklib/eg/prog/pi.awk new file mode 100644 index 00000000..3297beff --- /dev/null +++ b/awklib/eg/prog/pi.awk @@ -0,0 +1,18 @@ +# pi.awk --- compute the digits of pi +# +# Katie Wasserman, katie@wass.net +# August 2014 + +BEGIN { + digits = 100000 + two = 2 * 10 ^ digits + pi = two + for (m = digits * 4; m > 0; --m) { + d = m * 2 + 1 + x = pi * m + div(x, d, result) + pi = result["quotient"] + pi = pi + two + } + print pi +} diff --git a/awklib/eg/prog/split.awk b/awklib/eg/prog/split.awk index bcc73ae6..6a7198f6 100644 --- a/awklib/eg/prog/split.awk +++ b/awklib/eg/prog/split.awk @@ -50,9 +50,8 @@ BEGIN { } print > out } -function usage( e) +function usage() { - e = "usage: split [-num] [file] [outname]" - print e > "/dev/stderr" + print("usage: split [-num] [file] [outname]") > "/dev/stderr" exit 1 } diff --git a/awklib/eg/prog/uniq.awk b/awklib/eg/prog/uniq.awk index 2a2cf63e..7dd16099 100644 --- a/awklib/eg/prog/uniq.awk +++ b/awklib/eg/prog/uniq.awk @@ -5,10 +5,9 @@ # Arnold Robbins, arnold@skeeve.com, Public Domain # May 1993 -function usage( e) +function usage() { - e = "Usage: uniq [-udc [-n]] [+n] [ in [ out ]]" - print e > "/dev/stderr" + print("Usage: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr" exit 1 } @@ -2648,6 +2648,8 @@ struct cmdtoken cmdtab[] = { gettext_noop("up [N] - move N frames up the stack.") }, { "watch", "w", D_watch, D_WATCH, do_watch, gettext_noop("watch var - set a watchpoint for a variable.") }, +{ "where", "", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("where [N] - (same as backtrace) print trace of all or N innermost (outermost if N < 0) frames.") }, { NULL, NULL, D_illegal, 0, (Func_cmd) 0, NULL }, }; @@ -897,6 +897,8 @@ struct cmdtoken cmdtab[] = { gettext_noop("up [N] - move N frames up the stack.") }, { "watch", "w", D_watch, D_WATCH, do_watch, gettext_noop("watch var - set a watchpoint for a variable.") }, +{ "where", "", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("where [N] - (same as backtrace) print trace of all or N innermost (outermost if N < 0) frames.") }, { NULL, NULL, D_illegal, 0, (Func_cmd) 0, NULL }, }; @@ -326,6 +326,9 @@ /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL +/* enable severe portability problems */ +#undef I_DONT_KNOW_WHAT_IM_DOING + /* disable lint checks */ #undef NO_LINT @@ -761,6 +761,7 @@ enable_option_checking enable_silent_rules with_whiny_user_strftime enable_lint +enable_severe_portability_problems enable_dependency_tracking enable_largefile enable_nls @@ -1405,6 +1406,7 @@ Optional Features: --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --disable-lint Disable gawk lint checking + --enable-severe-portability-problems Enable really nasty portability problems --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking @@ -3181,6 +3183,17 @@ $as_echo "#define NO_LINT 1" >>confdefs.h fi +# Check whether --enable-severe-portability-problems was given. +if test "${enable_severe_portability_problems+set}" = set; then : + enableval=$enable_severe_portability_problems; if test "$enableval" = yes + then + +$as_echo "#define I_DONT_KNOW_WHAT_IM_DOING 1" >>confdefs.h + + fi + +fi + # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || @@ -10419,7 +10432,39 @@ fi $as_echo_n "checking whether readline via \"$_combo\" is present and sane... " >&6; } if test "$cross_compiling" = yes; then : - _found_readline=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +int +main () +{ + + int fd; + char *line; + + close(0); + close(1); + fd = open("/dev/null", 2); /* should get fd 0 */ + dup(fd); + line = readline("giveittome> "); + + /* some printfs don't handle NULL for %s */ + printf("got <%s>\n", line ? line : "(NULL)"); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + _found_readline=yes +else + _found_readline=no + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10953,7 +10998,7 @@ dylib) GAWKLIBEXT=so ;; # MacOS uses .dylib for shared libraries, but libtool us esac -ac_config_files="$ac_config_files Makefile awklib/Makefile doc/Makefile po/Makefile.in test/Makefile" +ac_config_files="$ac_config_files Makefile awklib/Makefile doc/Makefile extras/Makefile po/Makefile.in test/Makefile" if test "x$enable_extensions" = "xyes"; then @@ -11709,6 +11754,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "awklib/Makefile") CONFIG_FILES="$CONFIG_FILES awklib/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "extras/Makefile") CONFIG_FILES="$CONFIG_FILES extras/Makefile" ;; "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; diff --git a/configure.ac b/configure.ac index 510805c9..70074139 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,12 @@ AC_ARG_ENABLE([lint], [ --disable-lint Disable gawk lint checking], AC_DEFINE(NO_LINT, 1, [disable lint checks]) fi ) +AC_ARG_ENABLE([severe-portability-problems], [ --enable-severe-portability-problems Enable really nasty portability problems], + if test "$enableval" = yes + then + AC_DEFINE(I_DONT_KNOW_WHAT_IM_DOING, 1, [enable severe portability problems]) + fi +) AC_CANONICAL_HOST AC_USE_SYSTEM_EXTENSIONS @@ -397,6 +403,7 @@ AC_SUBST(GAWKLIBEXT) AC_CONFIG_FILES(Makefile awklib/Makefile doc/Makefile + extras/Makefile po/Makefile.in test/Makefile) if test "x$enable_extensions" = "xyes"; then @@ -3995,6 +3995,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) case Op_quotient_i: case Op_mod_i: case Op_assign_concat: + case Op_comment: print_memory(pc->memory, func, print_func, fp); /* fall through */ default: @@ -367,6 +367,9 @@ struct dfa token utf8_anychar_classes[5]; /* To lower ANYCHAR in UTF-8 locales. */ mbstate_t mbs; /* Multibyte conversion state. */ + /* dfaexec implementation. */ + char *(*dfaexec) (struct dfa *, char const *, char *, int, size_t *, int *); + /* The following are valid only if MB_CUR_MAX > 1. */ /* The value of multibyte_prop[i] is defined by following rule. @@ -429,6 +432,10 @@ struct dfa slots so far, not counting trans[-1]. */ int trcount; /* Number of transition tables that have actually been built. */ + int min_trcount; /* Minimum of number of transition tables. + Always keep the number, even after freeing + the transition tables. It is also the + number of initial states. */ state_num **trans; /* Transition tables for states that can never accept. If the transitions for a state have not yet been computed, or the @@ -447,6 +454,8 @@ struct dfa newline is stored separately and handled as a special case. Newline is also used as a sentinel at the end of the buffer. */ + state_num initstate_letter; /* Initial state for letter context. */ + state_num initstate_others; /* Initial state for other contexts. */ struct dfamust *musts; /* List of strings, at least one of which is known to appear in any r.e. matching the dfa. */ @@ -1296,6 +1305,20 @@ parse_bracket_exp (void) return CSET + charclass_index (ccl); } +#define PUSH_LEX_STATE(s) \ + do \ + { \ + char const *lexptr_saved = lexptr; \ + size_t lexleft_saved = lexleft; \ + lexptr = (s); \ + lexleft = strlen (lexptr) + +#define POP_LEX_STATE() \ + lexptr = lexptr_saved; \ + lexleft = lexleft_saved; \ + } \ + while (0) + static token lex (void) { @@ -1543,20 +1566,6 @@ lex (void) return lasttok = CSET + charclass_index (ccl); } -#define PUSH_LEX_STATE(s) \ - do \ - { \ - char const *lexptr_saved = lexptr; \ - size_t lexleft_saved = lexleft; \ - lexptr = (s); \ - lexleft = strlen (lexptr) - -#define POP_LEX_STATE() \ - lexptr = lexptr_saved; \ - lexleft = lexleft_saved; \ - } \ - while (0) - /* FIXME: see if optimizing this, as is done with ANYCHAR and add_utf8_anychar, makes sense. */ @@ -1576,14 +1585,33 @@ lex (void) case 'W': if (!backslash || (syntax_bits & RE_NO_GNU_OPS)) goto normal_char; - zeroset (ccl); - for (c2 = 0; c2 < NOTCHAR; ++c2) - if (IS_WORD_CONSTITUENT (c2)) - setbit (c2, ccl); - if (c == 'W') - notset (ccl); + + if (!dfa->multibyte) + { + zeroset (ccl); + for (c2 = 0; c2 < NOTCHAR; ++c2) + if (IS_WORD_CONSTITUENT (c2)) + setbit (c2, ccl); + if (c == 'W') + notset (ccl); + laststart = false; + return lasttok = CSET + charclass_index (ccl); + } + + /* FIXME: see if optimizing this, as is done with ANYCHAR and + add_utf8_anychar, makes sense. */ + + /* \w and \W are documented to be equivalent to [_[:alnum:]] and + [^_[:alnum:]] respectively, so tell the lexer to process those + strings, each minus its "already processed" '['. */ + PUSH_LEX_STATE (c == 'w' ? "_[:alnum:]]" : "^_[:alnum:]]"); + + lasttok = parse_bracket_exp (); + + POP_LEX_STATE (); + laststart = false; - return lasttok = CSET + charclass_index (ccl); + return lasttok; case '[': if (backslash) @@ -2585,9 +2613,16 @@ dfaanalyze (struct dfa *d, int searchflag) /* Build the initial state. */ separate_contexts = state_separate_contexts (&merged); - state_index (d, &merged, - (separate_contexts & CTX_NEWLINE - ? CTX_NEWLINE : separate_contexts ^ CTX_ANY)); + if (separate_contexts & CTX_NEWLINE) + state_index (d, &merged, CTX_NEWLINE); + d->initstate_others = d->min_trcount + = state_index (d, &merged, separate_contexts ^ CTX_ANY); + if (separate_contexts & CTX_LETTER) + d->initstate_letter = d->min_trcount + = state_index (d, &merged, CTX_LETTER); + else + d->initstate_letter = d->initstate_others; + d->min_trcount++; free (posalloc); free (stkalloc); @@ -2924,17 +2959,17 @@ build_state (state_num s, struct dfa *d) /* Set an upper limit on the number of transition tables that will ever exist at once. 1024 is arbitrary. The idea is that the frequently used transition tables will be quickly rebuilt, whereas the ones that - were only needed once or twice will be cleared away. However, do - not clear the initial state, as it's always used. */ + were only needed once or twice will be cleared away. However, do not + clear the initial D->min_trcount states, since they are always used. */ if (d->trcount >= 1024) { - for (i = 1; i < d->tralloc; ++i) + for (i = d->min_trcount; i < d->tralloc; ++i) { free (d->trans[i]); free (d->fails[i]); d->trans[i] = d->fails[i] = NULL; } - d->trcount = 1; + d->trcount = d->min_trcount; } ++d->trcount; @@ -3067,17 +3102,7 @@ match_mb_charset (struct dfa *d, state_num s, position pos, int context; /* Check syntax bits. */ - if (wc == (wchar_t) eolbyte) - { - if (!(syntax_bits & RE_DOT_NEWLINE)) - return 0; - } - else if (wc == (wchar_t) '\0') - { - if (syntax_bits & RE_DOT_NOT_NULL) - return 0; - } - else if (wc == WEOF) + if (wc == WEOF) return 0; context = wchar_context (wc); @@ -3309,6 +3334,31 @@ transit_state (struct dfa *d, state_num s, unsigned char const **pp, return s1; } +/* The initial state may encounter a byte which is not a single byte character + nor the first byte of a multibyte character. But it is incorrect for the + initial state to accept such a byte. For example, in Shift JIS the regular + expression "\\" accepts the codepoint 0x5c, but should not accept the second + byte of the codepoint 0x815c. Then the initial state must skip the bytes + that are not a single byte character nor the first byte of a multibyte + character. + + Given DFA state d, use mbs_to_wchar to advance MBP until it reaches or + exceeds P. If WCP is non-NULL, set *WCP to the final wide character + processed, or if no wide character is processed, set it to WEOF. + Both P and MBP must be no larger than END. */ +static unsigned char const * +skip_remains_mb (struct dfa *d, unsigned char const *p, + unsigned char const *mbp, char const *end, wint_t *wcp) +{ + wint_t wc = WEOF; + while (mbp < p) + mbp += mbs_to_wchar (&wc, (char const *) mbp, + end - (char const *) mbp, d); + if (wcp != NULL) + *wcp = wc; + return mbp; +} + /* Search through a buffer looking for a match to the given struct dfa. Find the first occurrence of a string matching the regexp in the buffer, and the shortest possible version thereof. Return a pointer to @@ -3320,10 +3370,14 @@ transit_state (struct dfa *d, state_num s, unsigned char const **pp, If COUNT is non-NULL, increment *COUNT once for each newline processed. Finally, if BACKREF is non-NULL set *BACKREF to indicate whether we encountered a back-reference (1) or not (0). The caller may use this - to decide whether to fall back on a backtracking matcher. */ -char * -dfaexec (struct dfa *d, char const *begin, char *end, - int allow_nl, size_t *count, int *backref) + to decide whether to fall back on a backtracking matcher. + + If MULTIBYTE, the input consists of multibyte characters and/or + encoding-error bytes. Otherwise, the input consists of single-byte + characters. */ +static inline char * +dfaexec_main (struct dfa *d, char const *begin, char *end, + int allow_nl, size_t *count, int *backref, bool multibyte) { state_num s, s1; /* Current state. */ unsigned char const *p, *mbp; /* Current input character. */ @@ -3345,7 +3399,7 @@ dfaexec (struct dfa *d, char const *begin, char *end, saved_end = *(unsigned char *) end; *end = eol; - if (d->multibyte) + if (multibyte) { memset (&d->mbs, 0, sizeof d->mbs); if (! d->mb_match_lens) @@ -3357,34 +3411,49 @@ dfaexec (struct dfa *d, char const *begin, char *end, for (;;) { - if (d->multibyte) + if (multibyte) { while ((t = trans[s]) != NULL) { s1 = s; - if (s == 0) + if (s < d->min_trcount) { - /* The initial state may encounter a byte which is not - a single byte character nor the first byte of a - multibyte character. But it is incorrect for the - initial state to accept such a byte. For example, - in Shift JIS the regular expression "\\" accepts - the codepoint 0x5c, but should not accept the second - byte of the codepoint 0x815c. Then the initial - state must skip the bytes that are not a single - byte character nor the first byte of a multibyte - character. */ - wint_t wc; - while (mbp < p) - mbp += mbs_to_wchar (&wc, (char const *) mbp, - end - (char const *) mbp, d); - p = mbp; - - if ((char *) p > end) + if (d->min_trcount == 1) { - p = NULL; - goto done; + if (d->states[s].mbps.nelem == 0) + { + do + { + while (t[*p] == 0) + p++; + p = mbp = skip_remains_mb (d, p, mbp, end, NULL); + } + while (t[*p] == 0); + } + else + p = mbp = skip_remains_mb (d, p, mbp, end, NULL); + } + else + { + wint_t wc; + mbp = skip_remains_mb (d, p, mbp, end, &wc); + + /* If d->min_trcount is greater than 1, maybe + transit to another initial state after skip. */ + if (p < mbp) + { + int context = wchar_context (wc); + if (context == CTX_LETTER) + s = d->initstate_letter; + else + /* It's CTX_NONE. CTX_NEWLINE cannot happen, + as we assume that a newline is always a + single byte character. */ + s = d->initstate_others; + p = mbp; + s1 = s; + } } } @@ -3394,25 +3463,60 @@ dfaexec (struct dfa *d, char const *begin, char *end, continue; } - /* Falling back to the glibc matcher in this case gives - better performance (up to 25% better on [a-z], for - example) and enables support for collating symbols and - equivalence classes. */ - if (d->states[s].has_mbcset && backref) - { - *backref = 1; - goto done; - } + /* The following code is used twice. + Use a macro to avoid the risk that they diverge. */ +#define State_transition() \ + do { \ + /* Falling back to the glibc matcher in this case gives \ + better performance (up to 25% better on [a-z], for \ + example) and enables support for collating symbols and \ + equivalence classes. */ \ + if (d->states[s].has_mbcset && backref) \ + { \ + *backref = 1; \ + goto done; \ + } \ + \ + /* Can match with a multibyte character (and multi-character \ + collating element). Transition table might be updated. */ \ + s = transit_state (d, s, &p, (unsigned char *) end); \ + \ + /* If previous character is newline after a transition \ + for ANYCHAR or MBCSET in non-UTF8 multibyte locales, \ + check whether current position is beyond the end of \ + the input buffer. Also, transit to initial state if \ + !ALLOW_NL, even if RE_DOT_NEWLINE is set. */ \ + if (p[-1] == eol) \ + { \ + if ((char *) p > end) \ + { \ + p = NULL; \ + goto done; \ + } \ + \ + nlcount++; \ + \ + if (!allow_nl) \ + s = 0; \ + } \ + \ + mbp = p; \ + trans = d->trans; \ + } while (0) - /* Can match with a multibyte character (and multi character - collating element). Transition table might be updated. */ - s = transit_state (d, s, &p, (unsigned char *) end); - mbp = p; - trans = d->trans; + State_transition(); } } else { + if (s == 0 && (t = trans[s]) != NULL) + { + while (t[*p] == 0) + p++; + s1 = 0; + s = t[*p++]; + } + while ((t = trans[s]) != NULL) { s1 = t[*p++]; @@ -3443,14 +3547,8 @@ dfaexec (struct dfa *d, char const *begin, char *end, } s1 = s; - if (d->multibyte) - { - /* Can match with a multibyte character (and multicharacter - collating element). Transition table might be updated. */ - s = transit_state (d, s, &p, (unsigned char *) end); - mbp = p; - trans = d->trans; - } + if (multibyte) + State_transition(); else s = d->fails[s][*p++]; continue; @@ -3488,6 +3586,33 @@ dfaexec (struct dfa *d, char const *begin, char *end, return (char *) p; } +/* Specialized versions of dfaexec_main for multibyte and single-byte + cases. This is for performance. */ + +static char * +dfaexec_mb (struct dfa *d, char const *begin, char *end, + int allow_nl, size_t *count, int *backref) +{ + return dfaexec_main (d, begin, end, allow_nl, count, backref, true); +} + +static char * +dfaexec_sb (struct dfa *d, char const *begin, char *end, + int allow_nl, size_t *count, int *backref) +{ + return dfaexec_main (d, begin, end, allow_nl, count, backref, false); +} + +/* Like dfaexec_main (D, BEGIN, END, ALLOW_NL, COUNT, BACKREF, D->multibyte), + but faster. */ + +char * +dfaexec (struct dfa *d, char const *begin, char *end, + int allow_nl, size_t *count, int *backref) +{ + return d->dfaexec (d, begin, end, allow_nl, count, backref); +} + struct dfa * dfasuperset (struct dfa const *d) { @@ -3537,6 +3662,7 @@ dfainit (struct dfa *d) { memset (d, 0, sizeof *d); d->multibyte = MB_CUR_MAX > 1; + d->dfaexec = d->multibyte ? dfaexec_mb : dfaexec_sb; d->fast = !d->multibyte; } @@ -3577,6 +3703,7 @@ dfaoptimize (struct dfa *d) free_mbdata (d); d->multibyte = false; + d->dfaexec = dfaexec_sb; } static void @@ -3590,6 +3717,7 @@ dfassbuild (struct dfa *d) *sup = *d; sup->multibyte = false; + sup->dfaexec = dfaexec_sb; sup->multibyte_prop = NULL; sup->mbcsets = NULL; sup->superset = NULL; diff --git a/doc/ChangeLog b/doc/ChangeLog index b917e642..6dfd1b17 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,118 @@ +2014-11-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Comment out that I need an owner for awk.info. + I may have found one or two people. + +2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in: Document new extras directory containing shell startup + files to manipulate AWKPATH and AWKLIBPATH environment variables. + +2014-10-28 Arnold D. Robbins <arnold@skeeve.com> + + * gawk.1: Clarification that debugger reads stdin. + * gawktexi.in: Ditto, and correctly place the "Braces" entry in + the Glossary. Thanks to Antonio Colombo for that. + + Unrelated: + + * gawktexi.in: Restore use of @sc. Karl fixed makeinfo. :-) + +2014-10-25 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Minor typo fixes. + Fix discussion of \x, per note from Antonio Colombo. + +2014-10-17 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Fix date in docbook attribution for new Foreword; + thanks to Antonio Columbo for the catch. Update latest version + of gettext. + +2014-10-15 Arnold D. Robbins <arnold@skeeve.com> + + * gawk.1: Fix default value for AWKLIBPATH. + * gawktexi.in: Revised text for AWKPATH and AWKLIBPATH. + +2014-10-14 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Add new Foreword from Mike Brennan. + +2014-10-13 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Fix example outputs in chapter 2. + Improve description of SYMTAB. + +2014-10-12 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Revise doc for {INT,STR}_CHAIN_MAX. Remove Pat + Rankin from VMS duties (per his request). Add a small TeX fix + for the table in ch 16 for requesting values. + +2014-10-05 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Finished changes! + +2014-10-03 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (EMRED): Renamed from EMISTERED to match original. + Thanks to Warren Toomey at TUHS for access to archives recording + the text. + +2014-10-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Pretty much done! + + Unrelated: + + * gawktexi.in: Fix braino in awk version of div function. + Thanks to Katie Wasserman for the catch. + +2014-10-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: More fixes after reading through the MS. + + Unrelated: + + * gawktexi.in: Add Katie Wasserman's program to compute + the digits of PI. + + Unrelated: + + * gawktexi.in: Document the differences between profiling + and pretty printing. + +2014-09-30 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: More fixes after reading through the MS. + +2014-09-29 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: More fixes after reading through the MS. + And still more fixes. + +2014-09-28 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: More fixes after reading through the MS. + Document the debugger's "where" command. + +2014-09-27 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Lots more fixes after reading through the MS. + +2014-09-23 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Rework the documentation of special files in + Chapter 5; some reordering as well as rewriting. + +2014-09-22 Arnold D. Robbins <arnold@skeeve.com> + + * gawktex.in: Continue fixes after reading through the MS. + +2014-09-21 Arnold D. Robbins <arnold@skeeve.com> + + * gawktex.in: Start on fixes after reading through the MS. + 2014-09-18 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Fix italics in quotations. Some docbook special @@ -231,7 +231,8 @@ and so on.) .PD \fB\-\^\-debug\fR[\fB=\fIfile\fR] Enable debugging of \*(AK programs. -By default, the debugger reads commands interactively from the terminal. +By default, the debugger reads commands interactively from the keyboard +(standard input). The optional .IR file argument specifies a file with a list @@ -626,7 +627,7 @@ specifies a search path to use when finding source files named with the .B \-l option. If this variable does not exist, the default path is -\fB".:/usr/local/lib/gawk"\fR. +\fB"/usr/local/lib/gawk"\fR. (The actual directory may vary, depending upon how .I gawk was built and installed.) diff --git a/doc/gawk.info b/doc/gawk.info index f1aa1f4a..5863ea0f 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -14,7 +14,7 @@ Free Software Foundation, Inc. This is Edition 4.1 of `GAWK: Effective AWK Programming: A User's -Guide for GNU Awk', for the 4.1.1 (or later) version of the GNU +Guide for GNU Awk', for the 4.1.2 (or later) version of the GNU implementation of AWK. Permission is granted to copy, distribute and/or modify this document @@ -29,7 +29,7 @@ entitled "GNU Free Documentation License". modify this GNU manual." -File: gawk.info, Node: Top, Next: Foreword, Up: (dir) +File: gawk.info, Node: Top, Next: Foreword3, Up: (dir) General Introduction ******************** @@ -42,7 +42,7 @@ Free Software Foundation, Inc. This is Edition 4.1 of `GAWK: Effective AWK Programming: A User's -Guide for GNU Awk', for the 4.1.1 (or later) version of the GNU +Guide for GNU Awk', for the 4.1.2 (or later) version of the GNU implementation of AWK. Permission is granted to copy, distribute and/or modify this document @@ -58,8 +58,9 @@ entitled "GNU Free Documentation License". * Menu: -* Foreword:: Some nice words about this +* Foreword3:: Some nice words about this Info file. +* Foreword4:: More nice words. * Preface:: What this Info file is about; brief history and acknowledgments. * Getting Started:: A basic introduction to using @@ -189,8 +190,8 @@ entitled "GNU Free Documentation License". * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting `FS' from the - command line. +* Command Line Field Separator:: Setting `FS' from the command + line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -234,10 +235,12 @@ entitled "GNU Free Documentation License". * Printf Examples:: Several examples. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in `gawk'. `gawk' allows access to inherited file descriptors. -* Special FD:: Special files for I/O. +* Other Inherited Files:: Accessing other open files with + `gawk'. * Special Network:: Special files for network communications. * Special Caveats:: Things to watch out for. @@ -330,7 +333,7 @@ entitled "GNU Free Documentation License". record. * Nextfile Statement:: Stop processing the current file. * Exit Statement:: Stop execution of `awk'. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * User-modified:: Built-in variables that you change to control `awk'. * Auto-set:: Built-in variables where `awk' @@ -350,12 +353,12 @@ entitled "GNU Free Documentation License". elements. * Controlling Scanning:: Controlling the order in which arrays are scanned. -* Delete:: The `delete' statement removes an - element from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in `awk'. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The `delete' statement removes an + element from an array. * Multidimensional:: Emulating multidimensional arrays in `awk'. * Multiscanning:: Scanning multidimensional arrays. @@ -414,6 +417,8 @@ entitled "GNU Free Documentation License". * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the + shell. * Data File Management:: Functions for managing command-line data files. * Filetrans Function:: A function for handling data file @@ -528,7 +533,6 @@ entitled "GNU Free Documentation License". * Extension API Description:: A full description of the API. * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with @@ -541,6 +545,7 @@ entitled "GNU Free Documentation License". * Two-way processors:: Registering a two-way processor. * Printing Messages:: Functions for printing messages. * Updating `ERRNO':: Functions for updating `ERRNO'. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -579,9 +584,9 @@ entitled "GNU Free Documentation License". processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to `gettimeofday()' and `sleep()'. +* Extension Sample API Tests:: Tests for the API. * gawkextlib:: The `gawkextlib' project. * Extension summary:: Extension summary. * Extension Exercises:: Exercises. @@ -610,6 +615,7 @@ entitled "GNU Free Documentation License". * Unix Installation:: Installing `gawk' under various versions of Unix. * Quick Installation:: Compiling `gawk' under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. * Non-Unix Installation:: Installation on Other Operating @@ -675,10 +681,10 @@ your life together with me. lives in innumerable ways. -File: gawk.info, Node: Foreword, Next: Preface, Prev: Top, Up: Top +File: gawk.info, Node: Foreword3, Next: Foreword4, Prev: Top, Up: Top -Foreword -******** +Foreword to the Third Edition +***************************** Arnold Robbins and I are good friends. We were introduced in 1990 by circumstances--and our favorite programming language, AWK. The @@ -693,7 +699,7 @@ on Unix, I found the gray AWK book, a.k.a. Aho, Kernighan and Weinberger, `The AWK Programming Language', Addison-Wesley, 1988. AWK's simple programming paradigm--find a pattern in the input and then perform an action--often reduced complex or tedious data manipulations -to few lines of code. I was excited to try my hand at programming in +to a few lines of code. I was excited to try my hand at programming in AWK. Alas, the `awk' on my computer was a limited version of the @@ -762,7 +768,41 @@ want to learn how, then read this book. March, 2001 -File: gawk.info, Node: Preface, Next: Getting Started, Prev: Foreword, Up: Top +File: gawk.info, Node: Foreword4, Next: Preface, Prev: Foreword3, Up: Top + +Foreword to the Fourth Edition +****************************** + +Some things don't change. Thirteen years ago I wrote: "If you use AWK +or want to learn how, then read this book." True then and still true +today. + + Learning to use a programming language is more than mastering the +syntax. One needs to acquire an understanding of how to use the +features of the language to solve practical programming problems. A +focus of this book is many examples that show how to use AWK. + + Some things do change. Our computers are much faster and have more +memory. Consequently, speed and storage inefficiencies of a high level +language matter less. Prototyping in AWK and then rewriting in C for +performance reasons happens less, because more often the prototype is +fast enough. + + Of course, there are computing operations that are best done in C or +C++. With `gawk' 4.1 and later, you do not have to choose between +writing your program in AWK or in C/C++. You can write most of your +program in AWK and the aspects that require C/C++ capabilities can be +written in C/C++ and then the pieces glued together when the `gawk' +module loads the C/C++ module as a dynamic plug-in. *note Dynamic +Extensions::, has all the details, and as expected, many examples to +help you learn the ins and outs. + + Michael Brennan + Author of `mawk' + October, 2014 + + +File: gawk.info, Node: Preface, Next: Getting Started, Prev: Foreword4, Up: Top Preface ******* @@ -775,14 +815,14 @@ rest of the file alone. Such jobs are often easy with `awk'. The makes it easy to handle simple data-reformatting jobs. The GNU implementation of `awk' is called `gawk'; if you invoke it -with the proper options or environment variables (*note Options::), it -is fully compatible with the POSIX(1) specification of the `awk' -language and with the Unix version of `awk' maintained by Brian -Kernighan. This means that all properly written `awk' programs should -work with `gawk'. Thus, we usually don't distinguish between `gawk' -and other `awk' implementations. +with the proper options or environment variables it is fully compatible +with the POSIX(1) specification of the `awk' language and with the Unix +version of `awk' maintained by Brian Kernighan. This means that all +properly written `awk' programs should work with `gawk'. So most of +the time, we don't distinguish between `gawk' and other `awk' +implementations. - Using `awk' allows you to: + Using `awk' you can: * Manage small, personal databases @@ -803,9 +843,9 @@ and other `awk' implementations. * Perform simple network communications - * Profile and debug `awk' programs. + * Profile and debug `awk' programs - * Extend the language with functions written in C or C++. + * Extend the language with functions written in C or C++ This Info file teaches you about the `awk' language and how you can use it effectively. You should already be familiar with basic system @@ -818,9 +858,8 @@ different computing environments. This Info file, while describing the of `awk' called `gawk' (which stands for "GNU `awk'"). `gawk' runs on a broad range of Unix systems, ranging from Intel-architecture PC-based computers up through large-scale systems. `gawk' has also been ported -to Mac OS X, Microsoft Windows (all versions) and OS/2 PCs, and OpenVMS. -(Some other, obsolete systems to which `gawk' was once ported are no -longer supported and the code for those systems has been removed.) +to Mac OS X, Microsoft Windows (all versions) and OS/2 PCs, and +OpenVMS.(3) * Menu: @@ -840,11 +879,14 @@ longer supported and the code for those systems has been removed.) (1) The 2008 POSIX standard is accessible online at `http://www.opengroup.org/onlinepubs/9699919799/'. - (2) These commands are available on POSIX-compliant systems, as well -as on traditional Unix-based systems. If you are using some other + (2) These utilities are available on POSIX-compliant systems, as +well as on traditional Unix-based systems. If you are using some other operating system, you still need to be familiar with the ideas of I/O redirection and pipes. + (3) Some other, obsolete systems to which `gawk' was once ported are +no longer supported and the code for those systems has been removed. + File: gawk.info, Node: History, Next: Names, Up: Preface @@ -872,16 +914,16 @@ V Release 3.1 (1987). The version in System V Release 4 (1989) added some new features and cleaned up the behavior in some of the "dark corners" of the language. The specification for `awk' in the POSIX Command Language and Utilities standard further clarified the language. -Both the `gawk' designers and the original Bell Laboratories `awk' -designers provided feedback for the POSIX specification. +Both the `gawk' designers and the original `awk' designers at Bell +Laboratories provided feedback for the POSIX specification. - Paul Rubin wrote the GNU implementation, `gawk', in 1986. Jay -Fenlason completed it, with advice from Richard Stallman. John Woods -contributed parts of the code as well. In 1988 and 1989, David -Trueman, with help from me, thoroughly reworked `gawk' for compatibility -with the newer `awk'. Circa 1994, I became the primary maintainer. -Current development focuses on bug fixes, performance improvements, -standards compliance and, occasionally, new features. + Paul Rubin wrote `gawk' in 1986. Jay Fenlason completed it, with +advice from Richard Stallman. John Woods contributed parts of the code +as well. In 1988 and 1989, David Trueman, with help from me, +thoroughly reworked `gawk' for compatibility with the newer `awk'. +Circa 1994, I became the primary maintainer. Current development +focuses on bug fixes, performance improvements, standards compliance +and, occasionally, new features. In May of 1997, Ju"rgen Kahrs felt the need for network access from `awk', and with a little help from me, set about adding features to do @@ -894,8 +936,8 @@ the `gawk' distribution). His code finally became part of the main `awk'-level debugger. This version became available as `gawk' version 4.0, in 2011. - *Note Contributors::, for a complete list of those who made -important contributions to `gawk'. + *Note Contributors::, for a full list of those who made important +contributions to `gawk'. File: gawk.info, Node: Names, Next: This Manual, Prev: History, Up: Preface @@ -948,8 +990,8 @@ programming language. in the POSIX standard. It does so in the context of the `gawk' implementation. While doing so, it also attempts to describe important differences between `gawk' and other `awk' implementations.(1) Finally, -any `gawk' features that are not in the POSIX standard for `awk' are -noted. +it notes any `gawk' features that are not in the POSIX standard for +`awk'. There are sidebars scattered throughout the Info file. They add a more complete explanation of points that are relevant, but not likely @@ -958,7 +1000,7 @@ heading "sidebar." Most of the time, the examples use complete `awk' programs. Some of the more advanced sections show only the part of the `awk' program that -illustrates the concept currently being described. +illustrates the concept being described. While this Info file is aimed principally at people who have not been exposed to `awk', there is a lot of information here that even the `awk' @@ -994,7 +1036,7 @@ building blocks for getting most things done in a program. *note Patterns and Actions::, describes how to write patterns for matching records, actions for doing something when a record is matched, -and the built-in variables `awk' and `gawk' use. +and the predefined variables `awk' and `gawk' use. *note Arrays::, covers `awk''s one-and-only data structure: associative arrays. Deleting array elements and whole arrays is also @@ -1002,7 +1044,8 @@ described, as well as sorting arrays in `gawk'. It also describes how `gawk' provides arrays of arrays. *note Functions::, describes the built-in functions `awk' and `gawk' -provide, as well as how to define your own functions. +provide, as well as how to define your own functions. It also +discusses how `gawk' lets you call functions indirectly. Part II shows how to use `awk' and `gawk' for problem solving. There is lots of code here for you to read and learn from. It contains @@ -1019,18 +1062,18 @@ problems. Part III focuses on features specific to `gawk'. It contains the following chapters: - *note Advanced Features::, describes a number of `gawk'-specific -advanced features. Of particular note are the abilities to have -two-way communications with another process, perform TCP/IP networking, -and profile your `awk' programs. + *note Advanced Features::, describes a number of advanced features. +Of particular note are the abilities to control the order of array +traversal, have two-way communications with another process, perform +TCP/IP networking, and profile your `awk' programs. - *note Internationalization::, describes special features in `gawk' -for translating program messages into different languages at runtime. + *note Internationalization::, describes special features for +translating program messages into different languages at runtime. - *note Debugger::, describes the `awk' debugger. + *note Debugger::, describes the `gawk' debugger. *note Arbitrary Precision Arithmetic::, describes advanced -arithmetic facilities provided by `gawk'. +arithmetic facilities. *note Dynamic Extensions::, describes how to add new variables and functions to `gawk' by writing extensions in C or C++. @@ -1117,8 +1160,8 @@ at all. Descriptions of such features (often called "dark corners") are noted in this Info file with "(d.c.)". They also appear in the index under the heading "dark corner." - As noted by the opening quote, though, any coverage of dark corners -is, by definition, incomplete. + But, as noted by the opening quote, any coverage of dark corners is +by definition incomplete. Extensions to the standard `awk' language that are supported by more than one `awk' implementation are marked "(c.e.)," and listed in the @@ -1158,7 +1201,7 @@ system for Intel, Power Architecture, Sun SPARC, IBM S/390, and other systems.(2) Many GNU/Linux distributions are available for download from the Internet. - The Info file itself has gone through a number of previous editions. + The Info file itself has gone through multiple previous editions. Paul Rubin wrote the very first draft of `The GAWK Manual'; it was around 40 pages in size. Diane Close and Richard Stallman improved it, yielding a version that was around 90 pages long and barely described @@ -1171,17 +1214,16 @@ published the first two editions under the title `The GNU Awk User's Guide'. This edition maintains the basic structure of the previous editions. -For FSF edition 4.0, the content has been thoroughly reviewed and -updated. All references to `gawk' versions prior to 4.0 have been -removed. Of significant note for this edition was *note Debugger::. +For FSF edition 4.0, the content was thoroughly reviewed and updated. +All references to `gawk' versions prior to 4.0 were removed. Of +significant note for that edition was *note Debugger::. For FSF edition 4.1, the content has been reorganized into parts, and the major new additions are *note Arbitrary Precision Arithmetic::, and *note Dynamic Extensions::. - This Info file will undoubtedly continue to evolve. An electronic -version comes with the `gawk' distribution from the FSF. If you find -an error in this Info file, please report it! *Note Bugs::, for + This Info file will undoubtedly continue to evolve. If you find an +error in this Info file, please report it! *Note Bugs::, for information on submitting problem reports electronically. ---------- Footnotes ---------- @@ -1217,9 +1259,6 @@ for several years. world, please see `http://awk.info/?contribute' for how to contribute it to the web site. - As of this writing, this website is in search of a maintainer; please -contact me if you are interested. - File: gawk.info, Node: Acknowledgments, Prev: How To Contribute, Up: Preface @@ -1286,12 +1325,14 @@ Michal Jaegermann, Ju"rgen Kahrs, Stepan Kasal, John Malmberg, Dave Pitts, Chet Ramey, Pat Rankin, Andrew Schorr, Corinna Vinschen, and Eli Zaretskii (in alphabetical order) make up the current `gawk' "crack portability team." Without their hard work and help, `gawk' would not -be nearly the fine program it is today. It has been and continues to -be a pleasure working with this team of fine people. +be nearly the robust, portable program it is today. It has been and +continues to be a pleasure working with this team of fine people. Notable code and documentation contributions were made by a number of people. *Note Contributors::, for the full list. + Thanks to Michael Brennan for the Foreword. + Thanks to Patrice Dumas for the new `makeinfo' program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. @@ -1457,21 +1498,21 @@ advice (from Douglas Adams's `The Hitchhiker's Guide to the Galaxy'), to keep you from worrying about the complexities of computer programming: - $ awk "BEGIN { print "Don\47t Panic!" }" + $ awk 'BEGIN { print "Don\47t Panic!" }' -| Don't Panic! `awk' executes statements associated with `BEGIN' before reading any input. If there are no other statements in your program, as is the case here, `awk' just stops, instead of trying to read input it doesn't -know how to process. The `\47' is a magic way of getting a single -quote into the program, without having to engage in ugly shell quoting -tricks. +know how to process. The `\47' is a magic way (explained later) of +getting a single quote into the program, without having to engage in +ugly shell quoting tricks. - NOTE: As a side note, if you use Bash as your shell, you should - execute the command `set +H' before running this program - interactively, to disable the C shell-style command history, which - treats `!' as a special character. We recommend putting this - command into your personal startup file. + NOTE: If you use Bash as your shell, you should execute the + command `set +H' before running this program interactively, to + disable the C shell-style command history, which treats `!' as a + special character. We recommend putting this command into your + personal startup file. This next simple `awk' program emulates the `cat' utility; it copies whatever you type on the keyboard to its standard output (why this @@ -1494,9 +1535,9 @@ File: gawk.info, Node: Long, Next: Executable Scripts, Prev: Read Terminal, 1.1.3 Running Long Programs --------------------------- -Sometimes your `awk' programs can be very long. In this case, it is -more convenient to put the program into a separate file. In order to -tell `awk' to use that file for its program, you type: +Sometimes `awk' programs are very long. In these cases, it is more +convenient to put the program into a separate file. In order to tell +`awk' to use that file for its program, you type: awk -f SOURCE-FILE INPUT-FILE1 INPUT-FILE2 ... @@ -1512,14 +1553,16 @@ into the file `advice'. Then this command: does the same thing as this one: - awk "BEGIN { print \"Don't Panic!\" }" + awk 'BEGIN { print "Don\47t Panic!" }' This was explained earlier (*note Read Terminal::). Note that you don't usually need single quotes around the file name that you specify with `-f', because most file names don't contain any of the shell's special characters. Notice that in `advice', the `awk' program did not have single quotes around it. The quotes are only needed for programs -that are provided on the `awk' command line. +that are provided on the `awk' command line. (Also, placing the +program in a file allows us to use a literal single quote in the program +text, instead of the magic `\47'.) If you want to clearly identify your `awk' program files as such, you can add the extension `.awk' to the file name. This doesn't affect @@ -1563,7 +1606,7 @@ program is written in `awk'. utility reads your program and then processes your data according to the instructions in your program. (This is different from a "compiled" language such as C, where your program is first compiled into machine -code that is executed directly by your system's hardware.) The `awk' +code that is executed directly by your system's processor.) The `awk' utility is thus termed an "interpreter". Many modern languages are interperted. @@ -1573,8 +1616,8 @@ to pass to that interpreter. The operating system then runs the interpreter with the given argument and the full argument list of the executed program. The first argument in the list is the full file name of the `awk' program. The rest of the argument list contains either -options to `awk', or data files, or both. Note that on many systems -`awk' may be found in `/usr/bin' instead of in `/bin'. Caveat Emptor. +options to `awk', or data files, or both. (Note that on many systems +`awk' may be found in `/usr/bin' instead of in `/bin'.) Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -1714,8 +1757,11 @@ the quoting rules. the characters `$', ``', `\', and `"', all of which must be preceded by a backslash within double-quoted text if they are to be passed on literally to the program. (The leading backslash is - stripped first.) Thus, the example seen in *note Read Terminal::, - is applicable: + stripped first.) Thus, the example seen in *note Read Terminal::: + + awk 'BEGIN { print "Don\47t Panic!" }' + + could instead be written this way: $ awk "BEGIN { print \"Don't Panic!\" }" -| Don't Panic! @@ -1733,10 +1779,10 @@ the quoting rules. awk -F"" 'PROGRAM' FILES # wrong! - In the second case, `awk' will attempt to use the text of the - program as the value of `FS', and the first file name as the text - of the program! This results in syntax errors at best, and - confusing behavior at worst. + In the second case, `awk' attempts to use the text of the program + as the value of `FS', and the first file name as the text of the + program! This results in syntax errors at best, and confusing + behavior at worst. Mixing single and double quotes is difficult. You have to resort to shell quoting tricks, like this: @@ -1781,6 +1827,9 @@ this: $ awk -v sq="'" 'BEGIN { print "Here is a single quote <" sq ">" }' -| Here is a single quote <'> + (Here, the two string constants and the value of `sq' are +concatenated into a single string which is printed by `print'.) + If you really need both single and double quotes in your `awk' program, it is probably best to move it into a separate file, where the shell won't be part of the picture, and you can say what you mean. @@ -1816,12 +1865,12 @@ The second data file, called `inventory-shipped', contains information about monthly shipments. In both files, each line is considered to be one "record". - In the data file `mail-list', each record contains the name of a -person, his/her phone number, his/her email-address, and a code for -their relationship with the author of the list. The columns are -aligned using spaces. An `A' in the last column means that the person -is an acquaintance. An `F' in the last column means that the person is -a friend. An `R' means that the person is a relative: + In `mail-list', each record contains the name of a person, his/her +phone number, his/her email-address, and a code for their relationship +with the author of the list. The columns are aligned using spaces. An +`A' in the last column means that the person is an acquaintance. An +`F' in the last column means that the person is a friend. An `R' means +that the person is a relative: Amelia 555-5553 amelia.zodiacusque@gmail.com F Anthony 555-3412 anthony.asserturo@hotmail.com A @@ -1939,7 +1988,7 @@ different ways to do the same things shown here: * Print the length of the longest line in `data': expand data | awk '{ if (x < length($0)) x = length($0) } - END { print "maximum line length is " x }' + END { print "maximum line length is " x }' This example differs slightly from the previous one: The input is processed by the `expand' utility to change TABs into spaces, so @@ -1962,7 +2011,7 @@ different ways to do the same things shown here: * Print the total number of bytes used by FILES: ls -l FILES | awk '{ x += $5 } - END { print "total bytes: " x }' + END { print "total bytes: " x }' * Print the total number of kilobytes used by FILES: @@ -1991,13 +2040,13 @@ File: gawk.info, Node: Two Rules, Next: More Complex, Prev: Very Simple, Up: ============================= The `awk' utility reads the input files one line at a time. For each -line, `awk' tries the patterns of each of the rules. If several -patterns match, then several actions execute in the order in which they -appear in the `awk' program. If no patterns match, then no actions run. +line, `awk' tries the patterns of each rule. If several patterns +match, then several actions execute in the order in which they appear +in the `awk' program. If no patterns match, then no actions run. After processing all the rules that match the line (and perhaps there are none), `awk' reads the next line. (However, *note Next -Statement::, and also *note Nextfile Statement::). This continues +Statement::, and also *note Nextfile Statement::.) This continues until the program reaches the end of the file. For example, the following `awk' program contains two rules: @@ -2061,11 +2110,11 @@ date the file was last modified. Its output looks like this: The first field contains read-write permissions, the second field contains the number of links to the file, and the third field -identifies the owner of the file. The fourth field identifies the group -of the file. The fifth field contains the size of the file in bytes. -The sixth, seventh, and eighth fields contain the month, day, and time, +identifies the file's owner. The fourth field identifies the file's +group. The fifth field contains the file's size in bytes. The sixth, +seventh, and eighth fields contain the month, day, and time, respectively, that the file was last modified. Finally, the ninth field -contains the file name.(1) +contains the file name. The `$6 == "Nov"' in our `awk' program is an expression that tests whether the sixth field of the output from `ls -l' matches the string @@ -2087,11 +2136,6 @@ displays your output. By manipulating fields and using `print' statements, you can produce some very useful and impressive-looking reports. - ---------- Footnotes ---------- - - (1) The `LC_ALL=C' is needed to produce this traditional-style -output from `ls'. - File: gawk.info, Node: Statements/Lines, Next: Other Features, Prev: More Complex, Up: Getting Started @@ -2388,7 +2432,7 @@ The following list describes options mandated by the POSIX standard: CAUTION: Using `-v' to set the values of the built-in variables may lead to surprising results. `awk' will reset the values of those variables as it needs to, possibly - ignoring any predefined value you may have given. + ignoring any initial value you may have given. `-W GAWK-OPT' Provide an implementation-specific option. This is the POSIX @@ -2439,9 +2483,9 @@ The following list describes options mandated by the POSIX standard: `-d'[FILE] `--dump-variables'[`='FILE] Print a sorted list of global variables, their types, and final - values to FILE. If no FILE is provided, print this list to the - file named `awkvars.out' in the current directory. No space is - allowed between the `-d' and FILE, if FILE is supplied. + values to FILE. If no FILE is provided, print this list to a file + named `awkvars.out' in the current directory. No space is allowed + between the `-d' and FILE, if FILE is supplied. Having a list of all global variables is a good way to look for typographical errors in your programs. You would also use this @@ -2455,10 +2499,10 @@ The following list describes options mandated by the POSIX standard: `--debug'[`='FILE] Enable debugging of `awk' programs (*note Debugging::). By default, the debugger reads commands interactively from the - keyboard. The optional FILE argument allows you to specify a file - with a list of commands for the debugger to execute - non-interactively. No space is allowed between the `-D' and FILE, - if FILE is supplied. + keyboard (standard input). The optional FILE argument allows you + to specify a file with a list of commands for the debugger to + execute non-interactively. No space is allowed between the `-D' + and FILE, if FILE is supplied. `-e' PROGRAM-TEXT `--source' PROGRAM-TEXT @@ -2504,7 +2548,7 @@ The following list describes options mandated by the POSIX standard: `-i' SOURCE-FILE `--include' SOURCE-FILE - Read `awk' source library from SOURCE-FILE. This option is + Read an `awk' source library from SOURCE-FILE. This option is completely equivalent to using the `@include' directive inside your program. This option is very similar to the `-f' option, but there are two important differences. First, when `-i' is used, @@ -2525,8 +2569,8 @@ The following list describes options mandated by the POSIX standard: not be specified in the extension name. The extension initialization routine should be named `dl_load()'. An alternative is to use the `@load' keyword inside the program to - load a shared library. This feature is described in detail in - *note Dynamic Extensions::. + load a shared library. This advanced feature is described in + detail in *note Dynamic Extensions::. `-L'[VALUE] `--lint'[`='VALUE] @@ -2562,6 +2606,8 @@ The following list describes options mandated by the POSIX standard: CAUTION: This option can severely break old programs. Use with care. + This option may disappear in a future version of `gawk'. + `-N' `--use-lc-numeric' Force the use of the locale's decimal point character when parsing @@ -2661,8 +2707,9 @@ it is, `awk' reads its program source from all of the named files, as if they had been concatenated together into one big file. This is useful for creating libraries of `awk' functions. These functions can be written once and then retrieved from a standard place, instead of -having to be included into each individual program. (As mentioned in -*note Definition Syntax::, function names must be unique.) +having to be included into each individual program. The `-i' option is +similar in this regard. (As mentioned in *note Definition Syntax::, +function names must be unique.) With standard `awk', library functions can still be used, even if the program is entered at the keyboard, by specifying `-f /dev/tty'. @@ -2719,14 +2766,17 @@ Any additional arguments on the command line are normally treated as input files to be processed in the order specified. However, an argument that has the form `VAR=VALUE', assigns the value VALUE to the variable VAR--it does not specify a file at all. (See *note Assignment -Options::.) +Options::.) In the following example, COUNT=1 is a variable assignment, +not a file name: + + awk -f program.awk file1 count=1 file2 - All these arguments are made available to your `awk' program in the -`ARGV' array (*note Built-in Variables::). Command-line options and -the program text (if present) are omitted from `ARGV'. All other -arguments, including variable assignments, are included. As each -element of `ARGV' is processed, `gawk' sets the variable `ARGIND' to -the index in `ARGV' of the current element. + All the command-line arguments are made available to your `awk' +program in the `ARGV' array (*note Built-in Variables::). Command-line +options and the program text (if present) are omitted from `ARGV'. All +other arguments, including variable assignments, are included. As +each element of `ARGV' is processed, `gawk' sets the variable `ARGIND' +to the index in `ARGV' of the current element. Changing `ARGC' and `ARGV' in your `awk' program lets you control how `awk' processes the input files; this is described in more detail @@ -2820,50 +2870,58 @@ File: gawk.info, Node: AWKPATH Variable, Next: AWKLIBPATH Variable, Up: Envir The previous minor node described how `awk' program files can be named on the command line with the `-f' option. In most `awk' -implementations, you must supply a precise path name for each program -file, unless the file is in the current directory. But in `gawk', if +implementations, you must supply a precise pathname for each program +file, unless the file is in the current directory. But with `gawk', if the file name supplied to the `-f' or `-i' options does not contain a directory separator `/', then `gawk' searches a list of directories (called the "search path"), one by one, looking for a file with the specified name. The search path is a string consisting of directory names separated by -colons(1). `gawk' gets its search path from the `AWKPATH' environment -variable. If that variable does not exist, `gawk' uses a default path, -`.:/usr/local/share/awk'.(2) +colons.(1) `gawk' gets its search path from the `AWKPATH' environment +variable. If that variable does not exist, or if it has an empty value, +`gawk' uses a default path (described shortly). The search path feature is particularly helpful for building libraries of useful `awk' functions. The library files can be placed in a standard directory in the default path and then specified on the -command line with a short file name. Otherwise, the full file name -would have to be typed for each file. +command line with a short file name. Otherwise, you would have to type +the full file name for each file. - By using the `-i' option, or the `-e' and `-f' options, your -command-line `awk' programs can use facilities in `awk' library files -(*note Library Functions::). Path searching is not done if `gawk' is -in compatibility mode. This is true for both `--traditional' and -`--posix'. *Note Options::. + By using the `-i' or `-f' options, your command-line `awk' programs +can use facilities in `awk' library files (*note Library Functions::). +Path searching is not done if `gawk' is in compatibility mode. This is +true for both `--traditional' and `--posix'. *Note Options::. - If the source code is not found after the initial search, the path -is searched again after adding the default `.awk' suffix to the file -name. + If the source code file is not found after the initial search, the +path is searched again after adding the suffix `.awk' to the file name. + + `gawk''s path search mechanism is similar to the shell's. (See `The +Bourne-Again SHell manual' (http://www.gnu.org/software/bash/manual/).) +It treats a null entry in the path as indicating the current directory. +(A null entry is indicated by starting or ending the path with a colon +or by placing two colons next to each other [`::'].) NOTE: To include the current directory in the path, either place - `.' explicitly in the path or write a null entry in the path. (A - null entry is indicated by starting or ending the path with a - colon or by placing two colons next to each other [`::'].) This - path search mechanism is similar to the shell's. (See `The - Bourne-Again SHell manual'. - (http://www.gnu.org/software/bash/manual/)) - - However, `gawk' always looks in the current directory _before_ - searching `AWKPATH', so there is no real reason to include the - current directory in the search path. - - If `AWKPATH' is not defined in the environment, `gawk' places its -default search path into `ENVIRON["AWKPATH"]'. This makes it easy to -determine the actual search path that `gawk' used from within an `awk' -program. + `.' as an entry in the path or write a null entry in the path. + + Different past versions of `gawk' would also look explicitly in + the current directory, either before or after the path search. As + of version 4.1.2, this no longer happens, and if you wish to look + in the current directory, you must include `.' either as a separate + entry, or as a null entry in the search path. + + The default value for `AWKPATH' is `.:/usr/local/share/awk'.(2) +Since `.' is included at the beginning, `gawk' searches first in the +current directory and then in `/usr/local/share/awk'. In practice, +this means that you will rarely need to change the value of `AWKPATH'. + + *Note Shell Startup Files::, for information on functions that help +to manipulate the `AWKPATH' variable. + + `gawk' places the value of the search path that it used into +`ENVIRON["AWKPATH"]'. This provides access to the actual search path +value from within an `awk' program. While you can change `ENVIRON["AWKPATH"]' within your `awk' program, this has no effect on the running program's behavior. This makes @@ -2895,6 +2953,18 @@ platform. For example, on GNU/Linux systems, the suffix `.so' is used. The search path specified is also used for extensions loaded via the `@load' keyword (*note Loading Shared Libraries::). + If `AWKLIBPATH' does not exist in the environment, or if it has an +empty value, `gawk' uses a default path; this is typically +`/usr/local/lib/gawk', although it can vary depending upon how `gawk' +was built. + + *Note Shell Startup Files::, for information on functions that help +to manipulate the `AWKLIBPATH' variable. + + `gawk' places the value of the search path that it used into +`ENVIRON["AWKLIBPATH"]'. This provides access to the actual search path +value from within an `awk' program. + File: gawk.info, Node: Other Environment Variables, Prev: AWKLIBPATH Variable, Up: Environment Variables @@ -2905,15 +2975,6 @@ A number of other environment variables affect `gawk''s behavior, but they are more specialized. Those in the following list are meant to be used by regular users. -`POSIXLY_CORRECT' - Causes `gawk' to switch to POSIX compatibility mode, disabling all - traditional and GNU extensions. *Note Options::. - -`GAWK_SOCK_RETRIES' - Controls the number of times `gawk' attempts to retry a two-way - TCP/IP (socket) connection before giving up. *Note TCP/IP - Networking::. - `GAWK_MSEC_SLEEP' Specifies the interval between connection retries, in milliseconds. On systems that do not support the `usleep()' system @@ -2923,6 +2984,15 @@ used by regular users. Specifies the time, in milliseconds, for `gawk' to wait for input before returning with an error. *Note Read Timeout::. +`GAWK_SOCK_RETRIES' + Controls the number of times `gawk' attempts to retry a two-way + TCP/IP (socket) connection before giving up. *Note TCP/IP + Networking::. + +`POSIXLY_CORRECT' + Causes `gawk' to switch to POSIX compatibility mode, disabling all + traditional and GNU extensions. *Note Options::. + The environment variables in the following list are meant for use by the `gawk' developers for testing and tuning. They are subject to change. The variables are: @@ -2934,7 +3004,7 @@ change. The variables are: the value should be a number, and `gawk' uses that number as the size of the buffer to allocate. (When this variable is not set, `gawk' uses the smaller of the file's size and the "default" - blocksize, which is usually the filesystems I/O blocksize.) + blocksize, which is usually the filesystem's I/O blocksize.) `AWK_HASH' If this variable exists with a value of `gst', `gawk' switches to @@ -2948,11 +3018,11 @@ change. The variables are: where I/O is performed in records, not in blocks. `GAWK_MSG_SRC' - If this variable exists, `gawk' includes the source file name and - line number from which warning and/or fatal messages are - generated. Its purpose is to help isolate the source of a - message, since there can be multiple places which produce the same - warning or error message. + If this variable exists, `gawk' includes the file name and line + number within the `gawk' source code from which warning and/or + fatal messages are generated. Its purpose is to help isolate the + source of a message, since there are multiple places which produce + the same warning or error message. `GAWK_NO_DFA' If this variable exists, `gawk' does not use the DFA regexp matcher @@ -2967,12 +3037,12 @@ change. The variables are: evaluation stack, when needed. `INT_CHAIN_MAX' - The average number of items `gawk' will maintain on a hash chain - for managing arrays indexed by integers. + The intended maximum number of items `gawk' will maintain on a + hash chain for managing arrays indexed by integers. `STR_CHAIN_MAX' - The average number of items `gawk' will maintain on a hash chain - for managing arrays indexed by strings. + The intended maximum number of items `gawk' will maintain on a + hash chain for managing arrays indexed by strings. `TIDYMEM' If this variable exists, `gawk' uses the `mtrace()' library calls @@ -3031,8 +3101,8 @@ and here is `test2': Running `gawk' with `test2' produces the following result: $ gawk -f test2 - -| This is file test1. - -| This is file test2. + -| This is script test1. + -| This is script test2. `gawk' runs the `test2' script which includes `test1' using the `@include' keyword. So, to include external `awk' source files you just @@ -3054,9 +3124,9 @@ namely `test3': Running `gawk' with the `test3' script produces the following results: $ gawk -f test3 - -| This is file test1. - -| This is file test2. - -| This is file test3. + -| This is script test1. + -| This is script test2. + -| This is script test3. The file name can, of course, be a pathname. For example: @@ -3126,7 +3196,8 @@ is useful for embedding inside an `awk' source file that requires access to an extension. *note Dynamic Extensions::, describes how to write extensions (in C -or C++) that can be loaded with either `@load' or the `-l' option. +or C++) that can be loaded with either `@load' or the `-l' option. It +also describes the `ordchr' extension. File: gawk.info, Node: Obsolete, Next: Undocumented, Prev: Loading Shared Libraries, Up: Invoking Gawk @@ -3177,7 +3248,8 @@ File: gawk.info, Node: Invoking Summary, Prev: Undocumented, Up: Invoking Gaw affects how `awk' processes input. * You can use a single minus sign (`-') to refer to standard input - on the command line. + on the command line. `gawk' also lets you use the special file + name `/dev/stdin'. * `gawk' pays attention to a number of environment variables. `AWKPATH', `AWKLIBPATH', and `POSIXLY_CORRECT' are the most @@ -3315,9 +3387,9 @@ or newline. While there is nothing to stop you from entering most unprintable characters directly in a string constant or regexp constant, they may look ugly. - The following table lists all the escape sequences used in `awk' and -what they represent. Unless noted otherwise, all these escape sequences -apply to both string constants and regexp constants: + The following list presents all the escape sequences used in `awk' +and what they represent. Unless noted otherwise, all these escape +sequences apply to both string constants and regexp constants: `\\' A literal backslash, `\'. @@ -3354,14 +3426,15 @@ apply to both string constants and regexp constants: hexadecimal digits (`0'-`9', and either `A'-`F' or `a'-`f'). A maximum of two digts are allowed after the `\x'. Any further hexadecimal digits are treated as simple letters or numbers. - (c.e.) + (c.e.) (The `\x' escape sequence is not allowed in POSIX awk.) CAUTION: In ISO C, the escape sequence continues until the first nonhexadecimal digit is seen. For many years, `gawk' would continue incorporating hexadecimal digits into the value until a non-hexadecimal digit or the end of the string was encountered. However, using more than two hexadecimal - digits produces + digits produced undefined results. As of version *FIXME:* + 4.3.0, only two digits are processed. `\/' A literal slash (necessary for regexp constants only). This @@ -3391,11 +3464,11 @@ normally be a regexp operator. For example, `/a\+b/' matches the three characters `a+b'. For complete portability, do not use a backslash before any -character not shown in the previous list. +character not shown in the previous list and that is not an operator. To summarize: - * The escape sequences in the table above are always processed first, + * The escape sequences in the list above are always processed first, for both string constants and regexp constants. This happens very early, as soon as `awk' reads your program. @@ -3453,7 +3526,7 @@ and converted into corresponding real characters as the very first step in processing regexps. Here is a list of metacharacters. All characters that are not escape -sequences and that are not listed in the table stand for themselves: +sequences and that are not listed in the following stand for themselves: `\' This is used to suppress the special meaning of a character when @@ -3539,7 +3612,7 @@ sequences and that are not listed in the table stand for themselves: To cause `*' to apply to a larger sub-expression, use parentheses: `(ph)*' matches `ph', `phph', `phphph' and so on. - Second, `*' finds as many repetititons as possible. If the text to + Second, `*' finds as many repetitions as possible. If the text to be matched is `phhhhhhhhhhhhhhooey', `ph*' matches all of the `h's. `+' @@ -3641,8 +3714,8 @@ matches either `d' or `]'. Additionally, if you place `]' right after the opening `[', the closing bracket is treated as one of the characters to be matched. - This treatment of `\' in bracket expressions is compatible with -other `awk' implementations and is also mandated by POSIX. The regular + The treatment of `\' in bracket expressions is compatible with other +`awk' implementations and is also mandated by POSIX. The regular expressions in `awk' are a superset of the POSIX specification for Extended Regular Expressions (EREs). POSIX EREs are based on the regular expressions accepted by the traditional `egrep' utility. @@ -3730,10 +3803,11 @@ Consider the following: echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }' - This example uses the `sub()' function (which we haven't discussed -yet; *note String Functions::) to make a change to the input record. -Here, the regexp `/a+/' indicates "one or more `a' characters," and the -replacement text is `<A>'. + This example uses the `sub()' function to make a change to the input +record. (`sub()' replaces the first instance of any text matched by +the first argument with the string provided as the second argument; +*note String Functions::). Here, the regexp `/a+/' indicates "one or +more `a' characters," and the replacement text is `<A>'. The input contains four `a' characters. `awk' (and POSIX) regular expressions always match the leftmost, _longest_ sequence of input @@ -3809,15 +3883,15 @@ constants," for several reasons: Using `\n' in Bracket Expressions of Dynamic Regexps - Some versions of `awk' do not allow the newline character to be used -inside a bracket expression for a dynamic regexp: + Some older versions of `awk' do not allow the newline character to +be used inside a bracket expression for a dynamic regexp: $ awk '$0 ~ "[ \t\n]"' error--> awk: newline in character class [ error--> ]... error--> source line number 1 error--> context is - error--> >>> <<< + error--> $0 ~ "[ >>> \t\n]" <<< But a newline in a regexp constant works with no problem: @@ -3916,7 +3990,7 @@ No options Traditional Unix `awk' regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (`[[:alnum:]]', etc.) are supported, as - BWK `awk' does support them. Characters described by octal and + BWK `awk' supports them. Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. @@ -4025,10 +4099,6 @@ File: gawk.info, Node: Regexp Summary, Prev: Case-sensitivity, Up: Regexp Within bracket expressions, POSIX character classes let you specify certain groups of characters in a locale-independent fashion. - * `gawk''s `IGNORECASE' variable lets you control the case - sensitivity of regexp matching. In other `awk' versions, use - `tolower()' or `toupper()'. - * Regular expressions match the leftmost longest text in the string being matched. This matters for cases where you need to know the extent of the match, such as for text substitution and when the @@ -4037,6 +4107,10 @@ File: gawk.info, Node: Regexp Summary, Prev: Case-sensitivity, Up: Regexp * Matching expressions may use dynamic regexps, that is, string values treated as regular expressions. + * `gawk''s `IGNORECASE' variable lets you control the case + sensitivity of regexp matching. In other `awk' versions, use + `tolower()' or `toupper()'. + File: gawk.info, Node: Reading Files, Next: Printing, Prev: Regexp, Up: Top @@ -4049,8 +4123,8 @@ standard input (by default, this is the keyboard, but often it is a pipe from another command) or from files whose names you specify on the `awk' command line. If you specify input files, `awk' reads them in order, processing all the data from one before going on to the next. -The name of the current input file can be found in the built-in variable -`FILENAME' (*note Built-in Variables::). +The name of the current input file can be found in the predefined +variable `FILENAME' (*note Built-in Variables::). The input is read in units called "records", and is processed by the rules of your program one record at a time. By default, each record is @@ -4089,9 +4163,9 @@ File: gawk.info, Node: Records, Next: Fields, Up: Reading Files `awk' divides the input for your program into records and fields. It keeps track of the number of records that have been read so far from -the current input file. This value is stored in a built-in variable -called `FNR' which is reset to zero when a new file is started. -Another built-in variable, `NR', records the total number of input +the current input file. This value is stored in a predefined variable +called `FNR' which is reset to zero every time a new file is started. +Another predefined variable, `NR', records the total number of input records read so far from all data files. It starts at zero, but is never automatically reset to zero. @@ -4110,7 +4184,7 @@ Records are separated by a character called the "record separator". By default, the record separator is the newline character. This is why records are, by default, single lines. A different character can be used for the record separator by assigning the character to the -built-in variable `RS'. +predefined variable `RS'. Like any other variable, the value of `RS' can be changed in the `awk' program with the assignment operator, `=' (*note Assignment @@ -4198,9 +4272,10 @@ character such as `/' is more likely to produce correct behavior in the majority of cases, but there are no guarantees. The moral is: Know Your Data. - There is one unusual case, that occurs when `gawk' is being fully -POSIX-compliant (*note Options::). Then, the following (extreme) -pipeline prints a surprising `1': + When using regular characters as the record separator, there is one +unusual case that occurs when `gawk' is being fully POSIX-compliant +(*note Options::). Then, the following (extreme) pipeline prints a +surprising `1': $ echo | gawk --posix 'BEGIN { RS = "a" } ; { print NF }' -| 1 @@ -4265,9 +4340,9 @@ trailing whitespace: -| ] The square brackets delineate the contents of `RT', letting you see the -leading and trailing whitespace. The final value of `RT' `RT' is a -newline. *Note Simple Sed::, for a more useful example of `RS' as a -regexp and `RT'. +leading and trailing whitespace. The final value of `RT' is a newline. +*Note Simple Sed::, for a more useful example of `RS' as a regexp and +`RT'. If you set `RS' to a regular expression that allows optional trailing text, such as `RS = "abc(XYZ)?"' it is possible, due to @@ -4282,13 +4357,13 @@ that this will never happen. the beginning and end of a _line_. As a result, something like `RS = "^[[:upper:]]"' can only match at the beginning of a file. This is because `gawk' views the input file as one long string - that happens to contain newline characters in it. It is thus best - to avoid anchor characters in the value of `RS'. + that happens to contain newline characters. It is thus best to + avoid anchor characters in the value of `RS'. The use of `RS' as a regular expression and the `RT' variable are `gawk' extensions; they are not available in compatibility mode (*note Options::). In compatibility mode, only the first character of the -value of `RS' is used to determine the end of the record. +value of `RS' determines the end of the record. `RS = "\0"' Is Not Portable @@ -4317,11 +4392,12 @@ terminator. In effect, this means that `RS = "\0"' is the same as `RS It happens that recent versions of `mawk' can use the NUL character as a record separator. However, this is a special case: `mawk' does not -allow embedded NUL characters in strings. +allow embedded NUL characters in strings. (This may change in a future +version of `mawk'.) - *Note Readfile Function::, for an interesting, portable way to read -whole files. If you are using `gawk', see *note Extension Sample -Readfile::, for another option. + *Note Readfile Function::, for an interesting way to read whole +files. If you are using `gawk', see *note Extension Sample Readfile::, +for another option. ---------- Footnotes ---------- @@ -4360,7 +4436,7 @@ Here the first field, or `$1', is `This', the second field, or `$2', is Because there is no space between the `e' and the `.', the period is considered part of the seventh field. - `NF' is a built-in variable whose value is the number of fields in + `NF' is a predefined variable whose value is the number of fields in the current record. `awk' automatically updates the value of `NF' each time it reads a record. No matter how many fields there are, the last field in a record can be represented by `$NF'. So, `$NF' is the same @@ -4378,13 +4454,11 @@ examples: -| Julie 555-6699 julie.perscrutabor@skeeve.com F This example prints each record in the file `mail-list' whose first -field contains the string `li'. The operator `~' is called a "matching -operator" (*note Regexp Usage::); it tests whether a string (here, the -field `$1') matches a given regular expression. +field contains the string `li'. By contrast, the following example looks for `li' in _the entire -record_ and prints the first field and the last field for each matching -input record: +record_ and prints the first and last fields for each matching input +record: $ awk '/li/ { print $1, $NF }' mail-list -| Amelia F @@ -4439,9 +4513,9 @@ program. Other `awk' implementations may behave differently.) As mentioned in *note Fields::, `awk' stores the current record's number of fields in the built-in variable `NF' (also *note Built-in -Variables::). The expression `$NF' is not a special feature--it is the -direct consequence of evaluating `NF' and using its value as a field -number. +Variables::). Thus, the expression `$NF' is not a special feature--it +is the direct consequence of evaluating `NF' and using its value as a +field number. ---------- Footnotes ---------- @@ -4560,12 +4634,12 @@ value six. value of `NF' and recomputes `$0'. (d.c.) Here is an example: $ echo a b c d e f | awk '{ print "NF =", NF; - > NF = 3; print $0 }' + > NF = 3; print $0 }' -| NF = 6 -| a b c CAUTION: Some versions of `awk' don't rebuild `$0' when `NF' is - decremented. Caveat emptor. + decremented. Finally, there are times when it is convenient to force `awk' to rebuild the entire record, using the current value of the fields and @@ -4590,8 +4664,8 @@ as it was read from the input. This includes any leading or trailing whitespace, and the exact whitespace (or other characters) that separate the fields. - It is a not-uncommon error to try to change the field separators in -a record simply by setting `FS' and `OFS', and then expecting a plain + It is a common error to try to change the field separators in a +record simply by setting `FS' and `OFS', and then expecting a plain `print' or `print $0' to print the modified record. But this does not work, since nothing was done to change the record @@ -4628,7 +4702,7 @@ the following line: is split into three fields: `m', `*g', and `*gai*pan'. Note the leading spaces in the values of the second and third fields. - The field separator is represented by the built-in variable `FS'. + The field separator is represented by the predefined variable `FS'. Shell programmers take note: `awk' does _not_ use the name `IFS' that is used by the POSIX-compliant shells (such as the Unix Bourne shell, `sh', or Bash). @@ -4741,9 +4815,9 @@ play whenever `$0' is recomputed. For instance, study this pipeline: The first `print' statement prints the record as it was read, with leading whitespace intact. The assignment to `$2' rebuilds `$0' by concatenating `$1' through `$NF' together, separated by the value of -`OFS'. Because the leading whitespace was ignored when finding `$1', -it is not part of the new `$0'. Finally, the last `print' statement -prints the new `$0'. +`OFS' (which is a space by default). Because the leading whitespace +was ignored when finding `$1', it is not part of the new `$0'. +Finally, the last `print' statement prints the new `$0'. There is an additional subtlety to be aware of when using regular expressions for field splitting. It is not well-specified in the POSIX @@ -4758,7 +4832,7 @@ beginning of the record. `gawk' also works this way. For example: $ echo 'xxAA xxBxx C' | > gawk -F '(^x+)|( +)' '{ for (i = 1; i <= NF; i++) - > printf "-->%s<--\n", $i }' + > printf "-->%s<--\n", $i }' -| --><-- -| -->AA<-- -| -->xxBxx<-- @@ -4803,13 +4877,10 @@ For example: sets `FS' to the `,' character. Notice that the option uses an uppercase `F' instead of a lowercase `f'. The latter option (`-f') -specifies a file containing an `awk' program. Case is significant in -command-line options: the `-F' and `-f' options have nothing to do with -each other. You can use both options at the same time to set the `FS' -variable _and_ get an `awk' program from a file. +specifies a file containing an `awk' program. The value used for the argument to `-F' is processed in exactly the -same way as assignments to the built-in variable `FS'. Any special +same way as assignments to the predefined variable `FS'. Any special characters in the field separator must be escaped appropriately. For example, to use a `\' as the field separator on the command line, you would have to type: @@ -4904,7 +4975,7 @@ occurrences of any two characters." If instead you want fields to be separated by a literal period followed by any single character, use `FS = "\\.."'. - The following table summarizes how fields are split, based on the + The following list summarizes how fields are split, based on the value of `FS' (`==' means "is equal to"): `FS == " "' @@ -4924,7 +4995,7 @@ value of `FS' (`==' means "is equal to"): `FS == ""' Each individual character in the record becomes a separate field. - (This is a `gawk' extension; it is not specified by the POSIX + (This is a common extension; it is not specified by the POSIX standard.) Changing `FS' Does Not Affect the Fields @@ -5295,7 +5366,7 @@ A simple program to process this file is as follows: ... *Note Labels Program::, for a more realistic program that deals with -address lists. The following table summarizes how records are split, +address lists. The following list summarizes how records are split, based on the value of `RS'. (`==' means "is equal to.") `RS == "\n"' @@ -5319,9 +5390,10 @@ based on the value of `RS'. (`==' means "is equal to.") records. (This is a `gawk' extension; it is not specified by the POSIX standard.) - In all cases, `gawk' sets `RT' to the input text that matched the -value specified by `RS'. But if the input file ended without any text -that matches `RS', then `gawk' sets `RT' to the null string. + If not in compatibility mode (*note Options::), `gawk' sets `RT' to +the input text that matched the value specified by `RS'. But if the +input file ended without any text that matches `RS', then `gawk' sets +`RT' to the null string. ---------- Footnotes ---------- @@ -5400,9 +5472,7 @@ processing on the next record _right now_. For example: while (j == 0) { # get more text if (getline <= 0) { - m = "unexpected EOF or error" - m = (m ": " ERRNO) - print m > "/dev/stderr" + print("unexpected EOF or error:", ERRNO) > "/dev/stderr" exit } # build up the line using string concatenation @@ -5524,7 +5594,7 @@ Use `getline VAR < FILE' to read input from the file FILE, and put it in the variable VAR. As above, FILE is a string-valued expression that specifies the file from which to read. - In this version of `getline', none of the built-in variables are + In this version of `getline', none of the predefined variables are changed and the record is not split into fields. The only variable changed is VAR.(1) For example, the following program copies all the input files to the output, except for records that say @@ -5605,9 +5675,9 @@ the program might produce: bill ttyp1 Jul 13 14:23 (murphy:0) bletch -Notice that this program ran the command `who' and printed the previous -result. (If you try this program yourself, you will of course get -different results, depending upon who is logged in on your system.) +Notice that this program ran the command `who' and printed the result. +(If you try this program yourself, you will of course get different +results, depending upon who is logged in on your system.) This variation of `getline' splits the record into fields, sets the value of `NF', and recomputes the value of `$0'. The values of `NR' @@ -5623,10 +5693,10 @@ all `awk' implementations. NOTE: Unfortunately, `gawk' has not been consistent in its treatment of a construct like `"echo " "date" | getline'. Most versions, including the current version, treat it at as `("echo " - "date") | getline'. (This how BWK `awk' behaves.) Some versions - changed and treated it as `"echo " ("date" | getline)'. (This is - how `mawk' behaves.) In short, _always_ use explicit parentheses, - and then you won't have to worry. + "date") | getline'. (This is also how BWK `awk' behaves.) Some + versions changed and treated it as `"echo " ("date" | getline)'. + (This is how `mawk' behaves.) In short, _always_ use explicit + parentheses, and then you won't have to worry. File: gawk.info, Node: Getline/Variable/Pipe, Next: Getline/Coprocess, Prev: Getline/Pipe, Up: Getline @@ -5645,8 +5715,8 @@ following program reads the current date and time into the variable print "Report printed on " current_time } - In this version of `getline', none of the built-in variables are -changed and the record is not split into fields. + In this version of `getline', none of the predefined variables are +changed and the record is not split into fields. However, `RT' is set. According to POSIX, `EXPRESSION | getline VAR' is ambiguous if EXPRESSION contains unparenthesized operators other than `$'; for @@ -5695,7 +5765,7 @@ When you use `COMMAND |& getline VAR', the output from the coprocess COMMAND is sent through a two-way pipe to `getline' and into the variable VAR. - In this version of `getline', none of the built-in variables are + In this version of `getline', none of the predefined variables are changed and the record is not split into fields. The only variable changed is VAR. However, `RT' is set. @@ -5728,7 +5798,7 @@ in mind: `getline' command causes `awk' to set the value of `FILENAME'. Normally, `FILENAME' does not have a value inside `BEGIN' rules, because you have not yet started to process the command-line data - files. (d.c.) (*Note BEGIN/END::, also *note Auto-set::.) + files. (d.c.) (See *note BEGIN/END::; also *note Auto-set::.) * Using `FILENAME' with `getline' (`getline < FILENAME') is likely to be a source for confusion. `awk' opens a separate input stream @@ -5761,7 +5831,7 @@ in mind: `gawk' treats `getline' like a function call, and evaluates the expression `a[++c]' before attempting to read from `f'. However, some versions of `awk' only evaluate the expression once they know - that there is a string value to be assigned. Caveat Emptor. + that there is a string value to be assigned. File: gawk.info, Node: Getline Summary, Prev: Getline Notes, Up: Getline @@ -5770,23 +5840,22 @@ File: gawk.info, Node: Getline Summary, Prev: Getline Notes, Up: Getline ------------------------------------ *note table-getline-variants:: summarizes the eight variants of -`getline', listing which built-in variables are set by each one, and +`getline', listing which predefined variables are set by each one, and whether the variant is standard or a `gawk' extension. Note: for each -variant, `gawk' sets the `RT' built-in variable. +variant, `gawk' sets the `RT' predefined variable. -Variant Effect Standard / - Extension +Variant Effect `awk' / `gawk' ------------------------------------------------------------------------- -`getline' Sets `$0', `NF', `FNR', Standard +`getline' Sets `$0', `NF', `FNR', `awk' `NR', and `RT' -`getline' VAR Sets VAR, `FNR', `NR', and Standard +`getline' VAR Sets VAR, `FNR', `NR', and `awk' `RT' -`getline <' FILE Sets `$0', `NF', and `RT' Standard -`getline VAR < FILE' Sets VAR and `RT' Standard -COMMAND `| getline' Sets `$0', `NF', and `RT' Standard -COMMAND `| getline' VAR Sets VAR and `RT' Standard -COMMAND `|& getline' Sets `$0', `NF', and `RT' Extension -COMMAND `|& getline' Sets VAR and `RT' Extension +`getline <' FILE Sets `$0', `NF', and `RT' `awk' +`getline VAR < FILE' Sets VAR and `RT' `awk' +COMMAND `| getline' Sets `$0', `NF', and `RT' `awk' +COMMAND `| getline' VAR Sets VAR and `RT' `awk' +COMMAND `|& getline' Sets `$0', `NF', and `RT' `gawk' +COMMAND `|& getline' Sets VAR and `RT' `gawk' VAR Table 4.1: `getline' Variants and What They Set @@ -5802,7 +5871,7 @@ This minor node describes a feature that is specific to `gawk'. You may specify a timeout in milliseconds for reading input from the keyboard, a pipe, or two-way communication, including TCP/IP sockets. This can be done on a per input, command or connection basis, by -setting a special element in the `PROCINFO' (*note Auto-set::) array: +setting a special element in the `PROCINFO' array (*note Auto-set::): PROCINFO["input_name", "READ_TIMEOUT"] = TIMEOUT IN MILLISECONDS @@ -5826,9 +5895,9 @@ for more than five seconds: print $0 `gawk' terminates the read operation if input does not arrive after -waiting for the timeout period, returns failure and sets the `ERRNO' -variable to an appropriate string value. A negative or zero value for -the timeout is the same as specifying no timeout at all. +waiting for the timeout period, returns failure and sets `ERRNO' to an +appropriate string value. A negative or zero value for the timeout is +the same as specifying no timeout at all. A timeout can also be set for reading from the keyboard in the implicit loop that reads input records and matches them against @@ -5926,6 +5995,10 @@ File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-li A regexp Text that matches the `gawk' regexp + * `FNR' indicates how many records have been read from the current + input file; `NR' indicates how many records have been read in + total. + * `gawk' sets `RT' to the text matched by `RS'. * After splitting the input into records, `awk' further splits the @@ -5943,32 +6016,31 @@ File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-li * Field splitting is more complicated than record splitting. - Field separator value Fields are split ... `awk' / - `gawk' + Field separator value Fields are split ... `awk' / + `gawk' ---------------------------------------------------------------------- - `FS == " "' On runs of whitespace `awk' - `FS == ANY SINGLE On that character `awk' - CHARACTER' - `FS == REGEXP' On text matching the `awk' - regexp - `FS == ""' Each individual character `gawk' - is a separate field - `FIELDWIDTHS == LIST OF Based on character `gawk' - COLUMNS' position - `FPAT == REGEXP' On text around text `gawk' - matching the regexp - - Using `FS = "\n"' causes the entire record to be a single field + `FS == " "' On runs of whitespace `awk' + `FS == ANY SINGLE On that character `awk' + CHARACTER' + `FS == REGEXP' On text matching the regexp `awk' + `FS == ""' Each individual character is `gawk' + a separate field + `FIELDWIDTHS == LIST OF Based on character position `gawk' + COLUMNS' + `FPAT == REGEXP' On the text surrounding text `gawk' + matching the regexp + + * Using `FS = "\n"' causes the entire record to be a single field (assuming that newlines separate records). * `FS' may be set from the command line using the `-F' option. This can also be done using command-line variable assignment. - * `PROCINFO["FS"]' can be used to see how fields are being split. + * Use `PROCINFO["FS"]' to see how fields are being split. * Use `getline' in its various forms to read additional records, from the default input stream, from a file, or from a pipe or - co-process. + coprocess. * Use `PROCINFO[FILE, "READ_TIMEOUT"]' to cause reads to timeout for FILE. @@ -6026,6 +6098,7 @@ function. * Printf:: The `printf' statement. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in `gawk'. `gawk' allows access to inherited file descriptors. @@ -6039,10 +6112,10 @@ File: gawk.info, Node: Print, Next: Print Examples, Up: Printing 5.1 The `print' Statement ========================= -The `print' statement is used for producing output with simple, -standardized formatting. You specify only the strings or numbers to -print, in a list separated by commas. They are output, separated by -single spaces, followed by a newline. The statement looks like this: +Use the `print' statement to produce output with simple, standardized +formatting. You specify only the strings or numbers to print, in a +list separated by commas. They are output, separated by single spaces, +followed by a newline. The statement looks like this: print ITEM1, ITEM2, ... @@ -6057,14 +6130,14 @@ Numeric values are converted to strings and then printed. The simple statement `print' with no items is equivalent to `print $0': it prints the entire current record. To print a blank line, use -`print ""', where `""' is the empty string. To print a fixed piece of -text, use a string constant, such as `"Don't Panic"', as one item. If -you forget to use the double-quote characters, your text is taken as an -`awk' expression, and you will probably get an error. Keep in mind -that a space is printed between any two items. +`print ""'. To print a fixed piece of text, use a string constant, +such as `"Don't Panic"', as one item. If you forget to use the +double-quote characters, your text is taken as an `awk' expression, and +you will probably get an error. Keep in mind that a space is printed +between any two items. Note that the `print' statement is a statement and not an -expression--you can't use it the pattern part of a pattern-action +expression--you can't use it in the pattern part of a PATTERN-ACTION statement, for example. @@ -6157,7 +6230,7 @@ As mentioned previously, a `print' statement contains a list of items separated by commas. In the output, the items are normally separated by single spaces. However, this doesn't need to be the case; a single space is simply the default. Any string of characters may be used as -the "output field separator" by setting the built-in variable `OFS'. +the "output field separator" by setting the predefined variable `OFS'. The initial value of this variable is the string `" "'--that is, a single space. @@ -6219,12 +6292,12 @@ to format numbers (or strings), and that there are a number of different ways in which numbers can be formatted. The different format specifications are discussed more fully in *note Control Letters::. - The built-in variable `OFMT' contains the default format -specification that `print' uses with `sprintf()' when it wants to -convert a number to a string for printing. The default value of `OFMT' -is `"%.6g"'. The way `print' prints numbers can be changed by -supplying different format specifications as the value of `OFMT', as -shown in the following example: + The predefined variable `OFMT' contains the format specification +that `print' uses with `sprintf()' when it wants to convert a number to +a string for printing. The default value of `OFMT' is `"%.6g"'. The +way `print' prints numbers can be changed by supplying a different +format specification for the value of `OFMT', as shown in the following +example: $ awk 'BEGIN { > OFMT = "%.0f" # print numbers as integers (rounds) @@ -6246,8 +6319,6 @@ by `print', use `printf'. With `printf' you can specify the width to use for each item, as well as various formatting choices for numbers (such as what output base to use, whether to print an exponent, whether to print a sign, and how many digits to print after the decimal point). -You do this by supplying a string, called the "format string", that -controls how and where to print the other arguments. * Menu: @@ -6266,10 +6337,10 @@ A simple `printf' statement looks like this: printf FORMAT, ITEM1, ITEM2, ... -The entire list of arguments may optionally be enclosed in parentheses. -The parentheses are necessary if any of the item expressions use the `>' -relational operator; otherwise, it can be confused with an output -redirection (*note Redirection::). +As print `print', the entire list of arguments may optionally be +enclosed in parentheses. Here too, the parentheses are necessary if any +of the item expressions use the `>' relational operator; otherwise, it +can be confused with an output redirection (*note Redirection::). The difference between `printf' and `print' is the FORMAT argument. This is an expression whose value is taken as a string; it specifies @@ -6290,10 +6361,10 @@ statements. For example: $ awk 'BEGIN { > ORS = "\nOUCH!\n"; OFS = "+" - > msg = "Dont Panic!" + > msg = "Don\47t Panic!" > printf "%s\n", msg > }' - -| Dont Panic! + -| Don't Panic! Here, neither the `+' nor the `OUCH' appear in the output message. @@ -6311,9 +6382,9 @@ print. The rest of the format specifier is made up of optional width. Here is a list of the format-control letters: `%c' - Print a number as an ASCII character; thus, `printf "%c", 65' - outputs the letter `A'. The output for a string value is the first - character of the string. + Print a number as a character; thus, `printf "%c", 65' outputs the + letter `A'. The output for a string value is the first character + of the string. NOTE: The POSIX standard says the first character of a string is printed. In locales with multibyte characters, `gawk' @@ -6406,7 +6477,7 @@ File: gawk.info, Node: Format Modifiers, Next: Printf Examples, Prev: Control A format specification can also include "modifiers" that can control how much of the item's value is printed, as well as how much space it gets. The modifiers come between the `%' and the format-control letter. -We will use the bullet symbol "*" in the following examples to represent +We use the bullet symbol "*" in the following examples to represent spaces in the output. Here are the possible modifiers, in the order in which they may appear: @@ -6426,8 +6497,7 @@ which they may appear: At first glance, this feature doesn't seem to be of much use. It is in fact a `gawk' extension, intended for use in translating messages at runtime. *Note Printf Ordering::, which describes how - and why to use positional specifiers. For now, we will not use - them. + and why to use positional specifiers. For now, we ignore them. `-' The minus sign, used before the width modifier (see later on in @@ -6457,10 +6527,10 @@ which they may appear: trailing zeros are not removed from the result. `0' - A leading `0' (zero) acts as a flag that indicates that output - should be padded with zeros instead of spaces. This applies only - to the numeric output formats. This flag only has an effect when - the field width is wider than the value to print. + A leading `0' (zero) acts as a flag indicating that output should + be padded with zeros instead of spaces. This applies only to the + numeric output formats. This flag only has an effect when the + field width is wider than the value to print. `'' A single quote or apostrophe character is a POSIX extension to ISO @@ -6608,14 +6678,14 @@ beginning of the `awk' program: awk 'BEGIN { print "Name Number" print "---- ------" } - { printf "%-10s %s\n", $1, $2 }' mail-list + { printf "%-10s %s\n", $1, $2 }' mail-list The above example mixes `print' and `printf' statements in the same program. Using just `printf' statements can produce the same results: awk 'BEGIN { printf "%-10s %s\n", "Name", "Number" printf "%-10s %s\n", "----", "------" } - { printf "%-10s %s\n", $1, $2 }' mail-list + { printf "%-10s %s\n", $1, $2 }' mail-list Printing each column heading with the same format specification used for the column elements ensures that the headings are aligned just like @@ -6627,10 +6697,10 @@ be emphasized by storing it in a variable, like this: awk 'BEGIN { format = "%-10s %s\n" printf format, "Name", "Number" printf format, "----", "------" } - { printf format, $1, $2 }' mail-list + { printf format, $1, $2 }' mail-list -File: gawk.info, Node: Redirection, Next: Special Files, Prev: Printf, Up: Printing +File: gawk.info, Node: Redirection, Next: Special FD, Prev: Printf, Up: Printing 5.6 Redirecting Output of `print' and `printf' ============================================== @@ -6640,7 +6710,7 @@ output, usually the screen. Both `print' and `printf' can also send their output to other places. This is called "redirection". NOTE: When `--sandbox' is specified (*note Options::), redirecting - output to files and pipes is disabled. + output to files, pipes and coprocesses is disabled. A redirection appears after the `print' or `printf' statement. Redirections in `awk' are written just like redirections in shell @@ -6711,16 +6781,10 @@ work identically for `printf': maintenance: report = "mail bug-system" - print "Awk script failed:", $0 | report - m = ("at record number " FNR " of " FILENAME) - print m | report + print("Awk script failed:", $0) | report + print("at record number", FNR, "of", FILENAME) | report close(report) - The message is built using string concatenation and saved in the - variable `m'. It's then sent down the pipeline to the `mail' - program. (The parentheses group the items to concatenate--see - *note Concatenation::.) - The `close()' function is called here because it's a good idea to close the pipe as soon as all the intended output has been sent to it. *Note Close Files And Pipes::, for more information. @@ -6786,40 +6850,30 @@ uppercase characters converted to lowercase (*note String Functions::). The program builds up a list of command lines, using the `mv' utility to rename the files. It then sends the list to the shell for execution. - -File: gawk.info, Node: Special Files, Next: Close Files And Pipes, Prev: Redirection, Up: Printing - -5.7 Special File Names in `gawk' -================================ - -`gawk' provides a number of special file names that it interprets -internally. These file names provide access to standard file -descriptors and TCP/IP networking. - -* Menu: - -* Special FD:: Special files for I/O. -* Special Network:: Special files for network communications. -* Special Caveats:: Things to watch out for. + *Note Shell Quoting::, for a function that can help in generating +command lines to be fed to the shell. -File: gawk.info, Node: Special FD, Next: Special Network, Up: Special Files +File: gawk.info, Node: Special FD, Next: Special Files, Prev: Redirection, Up: Printing -5.7.1 Special Files for Standard Descriptors --------------------------------------------- +5.7 Special Files for Standard Pre-Opened Data Streams +====================================================== Running programs conventionally have three input and output streams already available to them for reading and writing. These are known as the "standard input", "standard output", and "standard error output". -These streams are, by default, connected to your keyboard and screen, -but they are often redirected with the shell, via the `<', `<<', `>', -`>>', `>&', and `|' operators. Standard error is typically used for -writing error messages; the reason there are two separate streams, +These open streams (and any other open file or pipe) are often referred +to by the technical term "file descriptors". + + These streams are, by default, connected to your keyboard and +screen, but they are often redirected with the shell, via the `<', `<<', +`>', `>>', `>&', and `|' operators. Standard error is typically used +for writing error messages; the reason there are two separate streams, standard output and standard error, is so that they can be redirected separately. - In other implementations of `awk', the only way to write an error -message to standard error in an `awk' program is as follows: + In traditional implementations of `awk', the only way to write an +error message to standard error in an `awk' program is as follows: print "Serious error detected!" | "cat 1>&2" @@ -6834,19 +6888,18 @@ error messages to the screen, like this: (`/dev/tty' is a special file supplied by the operating system that is connected to your keyboard and screen. It represents the "terminal,"(1) which on modern systems is a keyboard and screen, not a serial console.) -This usually has the same effect but not always: although the standard -error stream is usually the screen, it can be redirected; when that -happens, writing to the screen is not correct. In fact, if `awk' is -run from a background job, it may not have a terminal at all. Then +This generally has the same effect but not always: although the +standard error stream is usually the screen, it can be redirected; when +that happens, writing to the screen is not correct. In fact, if `awk' +is run from a background job, it may not have a terminal at all. Then opening `/dev/tty' fails. - `gawk' provides special file names for accessing the three standard -streams. (c.e.) It also provides syntax for accessing any other -inherited open files. If the file name matches one of these special -names when `gawk' redirects input or output, then it directly uses the -stream that the file name stands for. These special file names work -for all operating systems that `gawk' has been ported to, not just -those that are POSIX-compliant: + `gawk', BWK `awk' and `mawk' provide special file names for +accessing the three standard streams. If the file name matches one of +these special names when `gawk' (or one of the others) redirects input +or output, then it directly uses the descriptor that the file name +stands for. These special file names work for all operating systems +that `gawk' has been ported to, not just those that are POSIX-compliant: `/dev/stdin' The standard input (file descriptor 0). @@ -6857,16 +6910,8 @@ those that are POSIX-compliant: `/dev/stderr' The standard error output (file descriptor 2). -`/dev/fd/N' - The file associated with file descriptor N. Such a file must be - opened by the program initiating the `awk' execution (typically - the shell). Unless special pains are taken in the shell from which - `gawk' is invoked, only descriptors 0, 1, and 2 are available. - - The file names `/dev/stdin', `/dev/stdout', and `/dev/stderr' are -aliases for `/dev/fd/0', `/dev/fd/1', and `/dev/fd/2', respectively. -However, they are more self-explanatory. The proper way to write an -error message in a `gawk' program is to use `/dev/stderr', like this: + With these facilities, the proper way to write an error message then +becomes: print "Serious error detected!" > "/dev/stderr" @@ -6874,21 +6919,60 @@ error message in a `gawk' program is to use `/dev/stderr', like this: redirection, the value must be a string. It is a common error to omit the quotes, which leads to confusing results. - Finally, using the `close()' function on a file name of the form -`"/dev/fd/N"', for file descriptor numbers above two, does actually -close the given file descriptor. - - The `/dev/stdin', `/dev/stdout', and `/dev/stderr' special files are -also recognized internally by several other versions of `awk'. + `gawk' does not treat these file names as special when in POSIX +compatibility mode. However, since BWK `awk' supports them, `gawk' does +support them even when invoked with the `--traditional' option (*note +Options::). ---------- Footnotes ---------- (1) The "tty" in `/dev/tty' stands for "Teletype," a serial terminal. -File: gawk.info, Node: Special Network, Next: Special Caveats, Prev: Special FD, Up: Special Files +File: gawk.info, Node: Special Files, Next: Close Files And Pipes, Prev: Special FD, Up: Printing + +5.8 Special File Names in `gawk' +================================ + +Besides access to standard input, stanard output, and standard error, +`gawk' provides access to any open file descriptor. Additionally, +there are special file names reserved for TCP/IP networking. -5.7.2 Special Files for Network Communications +* Menu: + +* Other Inherited Files:: Accessing other open files with + `gawk'. +* Special Network:: Special files for network communications. +* Special Caveats:: Things to watch out for. + + +File: gawk.info, Node: Other Inherited Files, Next: Special Network, Up: Special Files + +5.8.1 Accessing Other Open Files With `gawk' +-------------------------------------------- + +Besides the `/dev/stdin', `/dev/stdout', and `/dev/stderr' special file +names mentioned earlier, `gawk' provides syntax for accessing any other +inherited open file: + +`/dev/fd/N' + The file associated with file descriptor N. Such a file must be + opened by the program initiating the `awk' execution (typically + the shell). Unless special pains are taken in the shell from which + `gawk' is invoked, only descriptors 0, 1, and 2 are available. + + The file names `/dev/stdin', `/dev/stdout', and `/dev/stderr' are +essentially aliases for `/dev/fd/0', `/dev/fd/1', and `/dev/fd/2', +respectively. However, those names are more self-explanatory. + + Note that using `close()' on a file name of the form `"/dev/fd/N"', +for file descriptor numbers above two, does actually close the given +file descriptor. + + +File: gawk.info, Node: Special Network, Next: Special Caveats, Prev: Other Inherited Files, Up: Special Files + +5.8.2 Special Files for Network Communications ---------------------------------------------- `gawk' programs can open a two-way TCP/IP connection, acting as either @@ -6908,14 +6992,18 @@ mentioned here only for completeness. Full discussion is delayed until File: gawk.info, Node: Special Caveats, Prev: Special Network, Up: Special Files -5.7.3 Special File Name Caveats +5.8.3 Special File Name Caveats ------------------------------- -Here is a list of things to bear in mind when using the special file -names that `gawk' provides: +Here are some things to bear in mind when using the special file names +that `gawk' provides: - * Recognition of these special file names is disabled if `gawk' is in - compatibility mode (*note Options::). + * Recognition of the file names for the three standard pre-opened + files is disabled only in POSIX mode. + + * Recognition of the other special file names is disabled if `gawk' + is in compatibility mode (either `--traditional' or `--posix'; + *note Options::). * `gawk' _always_ interprets these special file names. For example, using `/dev/fd/4' for output actually writes on file descriptor 4, @@ -6928,7 +7016,7 @@ names that `gawk' provides: File: gawk.info, Node: Close Files And Pipes, Next: Output Summary, Prev: Special Files, Up: Printing -5.8 Closing Input and Output Redirections +5.9 Closing Input and Output Redirections ========================================= If the same file name or the same shell command is used with `getline' @@ -7042,7 +7130,8 @@ addition, `gawk' sets `ERRNO' to a string indicating the error. Note also that `close(FILENAME)' has no "magic" effects on the implicit loop that reads through the files named on the command line. It is, more likely, a close of a file that was never opened with a -redirection, so `awk' silently does nothing. +redirection, so `awk' silently does nothing, except return a negative +value. When using the `|&' operator to communicate with a coprocess, it is occasionally useful to be able to close one end of the two-way pipe @@ -7051,8 +7140,8 @@ to `close()'. As in any other call to `close()', the first argument is the name of the command or special file used to start the coprocess. The second argument should be a string, with either of the values `"to"' or `"from"'. Case does not matter. As this is an advanced -feature, a more complete discussion is delayed until *note Two-way -I/O::, which discusses it in more detail and gives an example. +feature, discussion is delayed until *note Two-way I/O::, which +describes it in more detail and gives an example. Using `close()''s Return Value @@ -7067,8 +7156,8 @@ value from `close()': (d.c.) `gawk' treats `close()' as a function. The return value is -1 if the argument names something that was never opened with a redirection, or if there is a system problem closing the file or process. In these -cases, `gawk' sets the built-in variable `ERRNO' to a string describing -the problem. +cases, `gawk' sets the predefined variable `ERRNO' to a string +describing the problem. In `gawk', when closing a pipe or coprocess (input or output), the return value is the exit status of the command.(2) Otherwise, it is the @@ -7095,8 +7184,8 @@ value. File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Close Files And Pipes, Up: Printing -5.9 Summary -=========== +5.10 Summary +============ * The `print' statement prints comma-separated expressions. Each expression is separated by the value of `OFS' and terminated by @@ -7108,20 +7197,20 @@ File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Close Fi flags that modify the behavior of the format control letters. * Output from both `print' and `printf' may be redirected to files, - pipes, and co-processes. + pipes, and coprocesses. * `gawk' provides special file names for access to standard input, output and error, and for network communications. - * Use `close()' to close open file, pipe and co-process redirections. - For co-processes, it is possible to close only one direction of the + * Use `close()' to close open file, pipe and coprocess redirections. + For coprocesses, it is possible to close only one direction of the communications. File: gawk.info, Node: Output Exercises, Prev: Output Summary, Up: Printing -5.10 Exercises +5.11 Exercises ============== 1. Rewrite the program: @@ -7351,7 +7440,7 @@ and: are exactly equivalent. One rather bizarre consequence of this rule is that the following Boolean expression is valid, but does not do what -the user probably intended: +its author probably intended: # Note that /foo/ is on the left of the ~ if (/foo/ ~ $1) print "found foo" @@ -7377,9 +7466,10 @@ of the `match()' function, and as the third argument of the `split()' and `patsplit()' functions (*note String Functions::). Modern implementations of `awk', including `gawk', allow the third argument of `split()' to be a regexp constant, but some older implementations do -not. (d.c.) This can lead to confusion when attempting to use regexp -constants as arguments to user-defined functions (*note User-defined::). -For example: +not. (d.c.) Because some built-in functions accept regexp constants +as arguments, it can be confusing when attempting to use regexp +constants as arguments to user-defined functions (*note +User-defined::). For example: function mysub(pat, repl, str, global) { @@ -7443,23 +7533,23 @@ variable's current value. Variables are given new values with "assignment operators", "increment operators", and "decrement operators". *Note Assignment Ops::. In addition, the `sub()' and `gsub()' functions can change a variable's value, and the `match()', -`patsplit()' and `split()' functions can change the contents of their +`split()' and `patsplit()' functions can change the contents of their array parameters. *Note String Functions::. A few variables have special built-in meanings, such as `FS' (the field separator), and `NF' (the number of fields in the current input -record). *Note Built-in Variables::, for a list of the built-in -variables. These built-in variables can be used and assigned just like -all other variables, but their values are also used or changed -automatically by `awk'. All built-in variables' names are entirely +record). *Note Built-in Variables::, for a list of the predefined +variables. These predefined variables can be used and assigned just +like all other variables, but their values are also used or changed +automatically by `awk'. All predefined variables' names are entirely uppercase. Variables in `awk' can be assigned either numeric or string values. The kind of value a variable holds can change over the life of a program. By default, variables are initialized to the empty string, which is zero if converted to a number. There is no need to explicitly -"initialize" a variable in `awk', which is what you would do in C and -in most other traditional languages. +initialize a variable in `awk', which is what you would do in C and in +most other traditional languages. File: gawk.info, Node: Assignment Options, Prev: Using Variables, Up: Variables @@ -7555,7 +7645,7 @@ the string as numerals: `"2.5"' converts to 2.5, `"1e3"' converts to interpreted as valid numbers convert to zero. The exact manner in which numbers are converted into strings is -controlled by the `awk' built-in variable `CONVFMT' (*note Built-in +controlled by the `awk' predefined variable `CONVFMT' (*note Built-in Variables::). Numbers are converted using the `sprintf()' function with `CONVFMT' as the format specifier (*note String Functions::). @@ -7634,8 +7724,8 @@ difference in behavior, on a GNU/Linux system: The `en_DK.utf-8' locale is for English in Denmark, where the comma acts as the decimal point separator. In the normal `"C"' locale, `gawk' -treats `4,321' as `4', while in the Danish locale, it's treated as the -full number, 4.321. +treats `4,321' as 4, while in the Danish locale, it's treated as the +full number including the fractional part, 4.321. Some earlier versions of `gawk' fully complied with this aspect of the standard. However, many users in non-English locales complained @@ -8017,8 +8107,7 @@ A workaround is: awk '/[=]=/' /dev/null - `gawk' does not have this problem; BWK `awk' and `mawk' also do not -(*note Other Versions::). + `gawk' does not have this problem; BWK `awk' and `mawk' also do not. File: gawk.info, Node: Increment Ops, Prev: Assignment Ops, Up: All Operators @@ -8195,9 +8284,9 @@ determine how they are compared. Variable typing follows these rules: STRING attribute. * Fields, `getline' input, `FILENAME', `ARGV' elements, `ENVIRON' - elements, and the elements of an array created by `patsplit()', - `split()' and `match()' that are numeric strings have the STRNUM - attribute. Otherwise, they have the STRING attribute. + elements, and the elements of an array created by `match()', + `split()' and `patsplit()' that are numeric strings have the + STRNUM attribute. Otherwise, they have the STRING attribute. Uninitialized variables also have the STRNUM attribute. * Attributes propagate across assignments but are not changed by any @@ -8247,21 +8336,21 @@ In contrast, the eight characters `" +3.14"' appearing in program text comprise a string constant. The following examples print `1' when the comparison between the two different constants is true, `0' otherwise: - $ echo ' +3.14' | gawk '{ print $0 == " +3.14" }' True + $ echo ' +3.14' | awk '{ print($0 == " +3.14") }' True -| 1 - $ echo ' +3.14' | gawk '{ print $0 == "+3.14" }' False + $ echo ' +3.14' | awk '{ print($0 == "+3.14") }' False -| 0 - $ echo ' +3.14' | gawk '{ print $0 == "3.14" }' False + $ echo ' +3.14' | awk '{ print($0 == "3.14") }' False -| 0 - $ echo ' +3.14' | gawk '{ print $0 == 3.14 }' True + $ echo ' +3.14' | awk '{ print($0 == 3.14) }' True -| 1 - $ echo ' +3.14' | gawk '{ print $1 == " +3.14" }' False + $ echo ' +3.14' | awk '{ print($1 == " +3.14") }' False -| 0 - $ echo ' +3.14' | gawk '{ print $1 == "+3.14" }' True + $ echo ' +3.14' | awk '{ print($1 == "+3.14") }' True -| 1 - $ echo ' +3.14' | gawk '{ print $1 == "3.14" }' False + $ echo ' +3.14' | awk '{ print($1 == "3.14") }' False -| 0 - $ echo ' +3.14' | gawk '{ print $1 == 3.14 }' True + $ echo ' +3.14' | awk '{ print($1 == 3.14) }' True -| 1 @@ -8314,8 +8403,9 @@ Unless `b' happens to be zero or the null string, the `if' part of the test always succeeds. Because the operators are so similar, this kind of error is very difficult to spot when scanning the source code. - The following table of expressions illustrates the kind of comparison -`gawk' performs, as well as what the result of the comparison is: + The following list of expressions illustrates the kinds of +comparisons `awk' performs, as well as what the result of each +comparison is: `1.5 <= 2.0' numeric comparison (true) @@ -8366,9 +8456,9 @@ regexp constant (`/'...`/') or an ordinary expression. In the latter case, the value of the expression as a string is used as a dynamic regexp (*note Regexp Usage::; also *note Computed Regexps::). - In modern implementations of `awk', a constant regular expression in -slashes by itself is also an expression. The regexp `/REGEXP/' is an -abbreviation for the following comparison expression: + A constant regular expression in slashes by itself is also an +expression. The regexp `/REGEXP/' is an abbreviation for the following +comparison expression: $0 ~ /REGEXP/ @@ -8384,9 +8474,9 @@ File: gawk.info, Node: POSIX String Comparison, Prev: Comparison Operators, U The POSIX standard says that string comparison is performed based on the locale's "collating order". This is the order in which characters -sort, as defined by the locale (for more discussion, *note Ranges and -Locales::). This order is usually very different from the results -obtained when doing straight character-by-character comparison.(1) +sort, as defined by the locale (for more discussion, *note Locales::). +This order is usually very different from the results obtained when +doing straight character-by-character comparison.(1) Because this behavior differs considerably from existing practice, `gawk' only implements it when in POSIX mode (*note Options::). Here @@ -8443,13 +8533,15 @@ Boolean operators are: `BOOLEAN1 || BOOLEAN2' True if at least one of BOOLEAN1 or BOOLEAN2 is true. For example, the following statement prints all records in the input - that contain _either_ `edu' or `li' or both: + that contain _either_ `edu' or `li': if ($0 ~ /edu/ || $0 ~ /li/) print The subexpression BOOLEAN2 is evaluated only if BOOLEAN1 is false. This can make a difference when BOOLEAN2 contains expressions that - have side effects. + have side effects. (Thus, this test never really distinguishes + records that contain both `edu' and `li'--as soon as `edu' is + matched, the full test succeeds.) `! BOOLEAN' True if BOOLEAN is false. For example, the following program @@ -8457,7 +8549,7 @@ Boolean operators are: variable is not defined: BEGIN { if (! ("HOME" in ENVIRON)) - print "no home!" } + print "no home!" } (The `in' operator is described in *note Reference to Elements::.) @@ -8680,7 +8772,7 @@ violates the precedence rules; for example, `$$0++--' is not a valid expression because the first `$' has higher precedence than the `++'; to avoid the problem the expression can be rewritten as `$($0++)--'. - This table presents `awk''s operators, in order of highest to lowest + This list presents `awk''s operators, in order of highest to lowest precedence: `('...`)' @@ -8755,8 +8847,8 @@ system about the local character set and language. The ISO C standard defines a default `"C"' locale, which is an environment that is typical of what many C programmers are used to. - Once upon a time, the locale setting used to affect regexp matching -(*note Ranges and Locales::), but this is no longer true. + Once upon a time, the locale setting used to affect regexp matching, +but this is no longer true (*note Ranges and Locales::). Locales can affect record splitting. For the normal case of `RS = "\n"', the locale is largely irrelevant. For other single-character @@ -8808,10 +8900,11 @@ File: gawk.info, Node: Expressions Summary, Prev: Locales, Up: Expressions * `awk' provides the usual arithmetic operators (addition, subtraction, multiplication, division, modulus), and unary plus and minus. It also provides comparison operators, boolean - operators, and regexp matching operators. String concatenation is - accomplished by placing two expressions next to each other; there - is no explicit operator. The three-operand `?:' operator provides - an "if-else" test within expressions. + operators, array membership testing, and regexp matching + operators. String concatenation is accomplished by placing two + expressions next to each other; there is no explicit operator. + The three-operand `?:' operator provides an "if-else" test within + expressions. * Assignment operators provide convenient shorthands for common arithmetic operations. @@ -8819,8 +8912,8 @@ File: gawk.info, Node: Expressions Summary, Prev: Locales, Up: Expressions * In `awk', a value is considered to be true if it is non-zero _or_ non-null. Otherwise, the value is false. - * A value's type is set upon each assignment and may change over its - lifetime. The type determines how it behaves in comparisons + * A variable's type is set upon each assignment and may change over + its lifetime. The type determines how it behaves in comparisons (string or numeric). * Function calls return a value which may be used as part of a larger @@ -8846,7 +8939,7 @@ File: gawk.info, Node: Patterns and Actions, Next: Arrays, Prev: Expressions, As you have already seen, each `awk' statement consists of a pattern with an associated action. This major node describes how you build patterns and actions, what kinds of things you can do within actions, -and `awk''s built-in variables. +and `awk''s predefined variables. The pattern-action rules and the statements available for use within actions form the core of `awk' programming. In a sense, everything @@ -8860,7 +8953,7 @@ top of. Now it's time to start building something useful. * Action Overview:: What goes into an action. * Statements:: Describes the various control statements in detail. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * Pattern Action Summary:: Patterns and Actions summary. @@ -8891,7 +8984,7 @@ summary of the types of `awk' patterns: number) or non-null (if a string). (*Note Expression Patterns::.) `BEGPAT, ENDPAT' - A pair of patterns separated by a comma, specifying a range of + A pair of patterns separated by a comma, specifying a "range" of records. The range includes both the initial record that matches BEGPAT and the final record that matches ENDPAT. (*Note Ranges::.) @@ -9102,7 +9195,7 @@ input is read. For example: $ awk ' > BEGIN { print "Analysis of \"li\"" } - > /li/ { ++n } + > /li/ { ++n } > END { print "\"li\" appears in", n, "records." }' mail-list -| Analysis of "li" -| "li" appears in 4 records. @@ -9171,9 +9264,10 @@ and `NF' were _undefined_ inside an `END' rule. The POSIX standard specifies that `NF' is available in an `END' rule. It contains the number of fields from the last input record. Most probably due to an oversight, the standard does not say that `$0' is also preserved, -although logically one would think that it should be. In fact, `gawk' -does preserve the value of `$0' for use in `END' rules. Be aware, -however, that BWK `awk', and possibly other implementations, do not. +although logically one would think that it should be. In fact, all of +BWK `awk', `mawk', and `gawk' preserve the value of `$0' for use in +`END' rules. Be aware, however, that some other implementations and +many older versions of Unix `awk' do not. The third point follows from the first two. The meaning of `print' inside a `BEGIN' or `END' rule is the same as always: `print $0'. If @@ -9242,9 +9336,9 @@ makes it possible to catch and process I/O errors at the level of the `awk' program. The `next' statement (*note Next Statement::) is not allowed inside -either a `BEGINFILE' or and `ENDFILE' rule. The `nextfile' statement -(*note Nextfile Statement::) is allowed only inside a `BEGINFILE' rule, -but not inside an `ENDFILE' rule. +either a `BEGINFILE' or an `ENDFILE' rule. The `nextfile' statement is +allowed only inside a `BEGINFILE' rule, but not inside an `ENDFILE' +rule. The `getline' statement (*note Getline::) is restricted inside both `BEGINFILE' and `ENDFILE': only redirected forms of `getline' are @@ -9279,9 +9373,9 @@ hold a pattern that the `awk' program searches for. There are two ways to get the value of the shell variable into the body of the `awk' program. - The most common method is to use shell quoting to substitute the -variable's value into the program inside the script. For example, -consider the following program: + A common method is to use shell quoting to substitute the variable's +value into the program inside the script. For example, consider the +following program: printf "Enter search pattern: " read pattern @@ -9472,18 +9566,18 @@ thing the `while' statement does is test the CONDITION. If the CONDITION is true, it executes the statement BODY. (The CONDITION is true when the value is not zero and not a null string.) After BODY has been executed, CONDITION is tested again, and if it is still true, BODY -is executed again. This process repeats until the CONDITION is no -longer true. If the CONDITION is initially false, the body of the loop -is never executed and `awk' continues with the statement following the -loop. This example prints the first three fields of each record, one -per line: - - awk '{ - i = 1 - while (i <= 3) { - print $i - i++ - } +executes again. This process repeats until the CONDITION is no longer +true. If the CONDITION is initially false, the body of the loop never +executes and `awk' continues with the statement following the loop. +This example prints the first three fields of each record, one per line: + + awk ' + { + i = 1 + while (i <= 3) { + print $i + i++ + } }' inventory-shipped The body of this loop is a compound statement enclosed in braces, @@ -9514,22 +9608,22 @@ the CONDITION is true. It looks like this: BODY while (CONDITION) - Even if the CONDITION is false at the start, the BODY is executed at + Even if the CONDITION is false at the start, the BODY executes at least once (and only once, unless executing BODY makes CONDITION true). Contrast this with the corresponding `while' statement: while (CONDITION) - BODY + BODY This statement does not execute BODY even once if the CONDITION is false to begin with. The following is an example of a `do' statement: { - i = 1 - do { - print $0 - i++ - } while (i <= 10) + i = 1 + do { + print $0 + i++ + } while (i <= 10) } This program prints each input record 10 times. However, it isn't a @@ -9558,9 +9652,10 @@ INCREMENT. Typically, INITIALIZATION sets a variable to either zero or one, INCREMENT adds one to it, and CONDITION compares it against the desired number of iterations. For example: - awk '{ - for (i = 1; i <= 3; i++) - print $i + awk ' + { + for (i = 1; i <= 3; i++) + print $i }' inventory-shipped This prints the first three fields of each input record, with one field @@ -9584,7 +9679,7 @@ whatsoever. For example, the following statement prints all the powers of two between 1 and 100: for (i = 1; i <= 100; i *= 2) - print i + print i If there is nothing to be done, any of the three expressions in the parentheses following the `for' keyword may be omitted. Thus, @@ -9842,11 +9937,11 @@ rules. *Note BEGINFILE/ENDFILE::. According to the POSIX standard, the behavior is undefined if the `next' statement is used in a `BEGIN' or `END' rule. `gawk' treats it -as a syntax error. Although POSIX permits it, most other `awk' -implementations don't allow the `next' statement inside function bodies -(*note User-defined::). Just as with any other `next' statement, a -`next' statement inside a function body reads the next record and -starts processing it with the first rule in the program. +as a syntax error. Although POSIX does not disallow it, most other +`awk' implementations don't allow the `next' statement inside function +bodies (*note User-defined::). Just as with any other `next' +statement, a `next' statement inside a function body reads the next +record and starts processing it with the first rule in the program. File: gawk.info, Node: Nextfile Statement, Next: Exit Statement, Prev: Next Statement, Up: Statements @@ -9890,17 +9985,17 @@ files, pipes, and coprocesses that are opened with redirections. It is not related to the main processing that `awk' does with the files listed in `ARGV'. - NOTE: For many years, `nextfile' was a `gawk' extension. As of + NOTE: For many years, `nextfile' was a common extension. In September, 2012, it was accepted for inclusion into the POSIX standard. See the Austin Group website (http://austingroupbugs.net/view.php?id=607). - The current version of BWK `awk', and `mawk' (*note Other -Versions::) also support `nextfile'. However, they don't allow the -`nextfile' statement inside function bodies (*note User-defined::). -`gawk' does; a `nextfile' inside a function body reads the next record -and starts processing it with the first rule in the program, just as -any other `nextfile' statement. + The current version of BWK `awk', and `mawk' also support +`nextfile'. However, they don't allow the `nextfile' statement inside +function bodies (*note User-defined::). `gawk' does; a `nextfile' +inside a function body reads the next record and starts processing it +with the first rule in the program, just as any other `nextfile' +statement. File: gawk.info, Node: Exit Statement, Prev: Nextfile Statement, Up: Statements @@ -9924,8 +10019,8 @@ stop immediately. An `exit' statement that is not part of a `BEGIN' or `END' rule stops the execution of any further automatic rules for the current record, skips reading any remaining input records, and executes the -`END' rule if there is one. Any `ENDFILE' rules are also skipped; they -are not executed. +`END' rule if there is one. `gawk' also skips any `ENDFILE' rules; +they do not execute. In such a case, if you don't want the `END' rule to do its job, set a variable to nonzero before the `exit' statement and check that @@ -9962,8 +10057,8 @@ statement with a nonzero argument, as shown in the following example: File: gawk.info, Node: Built-in Variables, Next: Pattern Action Summary, Prev: Statements, Up: Patterns and Actions -7.5 Built-in Variables -====================== +7.5 Predefined Variables +======================== Most `awk' variables are available to use for your own purposes; they never change unless your program assigns values to them, and they never @@ -9973,7 +10068,7 @@ of these automatically, so that they enable you to tell `awk' how to do certain things. Others are set automatically by `awk', so that they carry information from the internal workings of `awk' to your program. - This minor node documents all of `gawk''s built-in variables, most + This minor node documents all of `gawk''s predefined variables, most of which are also documented in the major nodes describing their areas of activity. @@ -10012,7 +10107,7 @@ description of each variable.) use binary I/O. Any other string value is treated the same as `"rw"', but causes `gawk' to generate a warning message. `BINMODE' is described in more detail in *note PC Using::. `mawk' - *note Other Versions::), also supports this variable, but only + (*note Other Versions::), also supports this variable, but only using numeric values. ``CONVFMT'' @@ -10095,9 +10190,8 @@ description of each variable.) printing with the `print' statement. It works by being passed as the first argument to the `sprintf()' function (*note String Functions::). Its default value is `"%.6g"'. Earlier versions of - `awk' also used `OFMT' to specify the format for converting - numbers to strings in general expressions; this is now done by - `CONVFMT'. + `awk' used `OFMT' to specify the format for converting numbers to + strings in general expressions; this is now done by `CONVFMT'. `OFS' This is the output field separator (*note Output Separators::). @@ -10206,8 +10300,8 @@ Options::), they are not special. the command line. While you can change the value of `ARGIND' within your `awk' - program, `gawk' automatically sets it to a new value when the next - file is opened. + program, `gawk' automatically sets it to a new value when it opens + the next file. `ENVIRON' An associative array containing the values of the environment. @@ -10257,9 +10351,9 @@ Options::), they are not special. Getline::) inside a `BEGIN' rule can give `FILENAME' a value. `FNR' - The current record number in the current file. `FNR' is - incremented each time a new record is read (*note Records::). It - is reinitialized to zero each time a new input file is started. + The current record number in the current file. `awk' increments + `FNR' each time it reads a new record (*note Records::). `awk' + resets `FNR' to zero each time it starts a new input file. `NF' The number of fields in the current input record. `NF' is set @@ -10283,8 +10377,8 @@ Options::), they are not special. `NR' The number of input records `awk' has processed since the - beginning of the program's execution (*note Records::). `NR' is - incremented each time a new record is read. + beginning of the program's execution (*note Records::). `awk' + increments `NR' each time it reads a new record. `PROCINFO #' The elements of this array provide access to information about the @@ -10349,7 +10443,7 @@ Options::), they are not special. `PROCINFO["sorted_in"]' If this element exists in `PROCINFO', its value controls the - order in which array indices will be processed by `for (INDEX + order in which array indices will be processed by `for (INDX in ARRAY)' loops. Since this is an advanced feature, we defer the full description until later; see *note Scanning an Array::. @@ -10367,7 +10461,7 @@ Options::), they are not special. The following additional elements in the array are available to provide information about the MPFR and GMP libraries if your - version of `gawk' supports arbitrary precision numbers (*note + version of `gawk' supports arbitrary precision arithmetic (*note Arbitrary Precision Arithmetic::): `PROCINFO["mpfr_version"]' @@ -10400,14 +10494,14 @@ Options::), they are not special. The `PROCINFO' array has the following additional uses: - * It may be used to cause coprocesses to communicate over - pseudo-ttys instead of through two-way pipes; this is - discussed further in *note Two-way I/O::. - * It may be used to provide a timeout when reading from any open input file, pipe, or coprocess. *Note Read Timeout::, for more information. + * It may be used to cause coprocesses to communicate over + pseudo-ttys instead of through two-way pipes; this is + discussed further in *note Two-way I/O::. + `RLENGTH' The length of the substring matched by the `match()' function (*note String Functions::). `RLENGTH' is set by invoking the @@ -10426,9 +10520,14 @@ Options::), they are not special. separator. It is set every time a record is read. `SYMTAB #' - An array whose indices are the names of all currently defined - global variables and arrays in the program. The array may be used - for indirect access to read or write the value of a variable: + An array whose indices are the names of all defined global + variables and arrays in the program. `SYMTAB' makes `gawk''s + symbol table visible to the `awk' programmer. It is built as + `gawk' parses the program and is complete before the program + starts to run. + + The array may be used for indirect access to read or write the + value of a variable: foo = 5 SYMTAB["foo"] = 4 @@ -10596,6 +10695,12 @@ Because `-q' is not a valid `gawk' option, it and the following `-v' are passed on to the `awk' program. (*Note Getopt Function::, for an `awk' library function that parses command-line options.) + When designing your program, you should choose options that don't +conflict with `gawk''s, since it will process any options that it +accepts before passing the rest of the command line on to your program. +Using `#!' with the `-E' option may help (*note Executable Scripts::, +and *note Options::). + File: gawk.info, Node: Pattern Action Summary, Prev: Built-in Variables, Up: Patterns and Actions @@ -10625,8 +10730,8 @@ File: gawk.info, Node: Pattern Action Summary, Prev: Built-in Variables, Up: * The control statements in `awk' are `if'-`else', `while', `for', and `do'-`while'. `gawk' adds the `switch' statement. There are - two flavors of `for' statement: one for for performing general - looping, and the other iterating through an array. + two flavors of `for' statement: one for performing general + looping, and the other for iterating through an array. * `break' and `continue' let you exit early or start the next iteration of a loop (or get out of a `switch'). @@ -10638,11 +10743,16 @@ File: gawk.info, Node: Pattern Action Summary, Prev: Built-in Variables, Up: * The `exit' statement terminates your program. When executed from an action (or function body) it transfers control to the `END' statements. From an `END' statement body, it exits immediately. - You may pass an optional numeric value to be used at `awk''s exit + You may pass an optional numeric value to be used as `awk''s exit status. - * Some built-in variables provide control over `awk', mainly for I/O. - Other variables convey information from `awk' to your program. + * Some predefined variables provide control over `awk', mainly for + I/O. Other variables convey information from `awk' to your + program. + + * `ARGC' and `ARGV' make the command-line arguments available to + your program. Manipulating them from a `BEGIN' rule lets you + control how `awk' will process the provided data files. @@ -10663,26 +10773,21 @@ about array usage. The major node moves on to discuss `gawk''s facility for sorting arrays, and ends with a brief description of `gawk''s ability to support true arrays of arrays. - `awk' maintains a single set of names that may be used for naming -variables, arrays, and functions (*note User-defined::). Thus, you -cannot have a variable and an array with the same name in the same -`awk' program. - * Menu: * Array Basics:: The basics of arrays. -* Delete:: The `delete' statement removes an element - from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in `awk'. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The `delete' statement removes an element + from an array. * Multidimensional:: Emulating multidimensional arrays in `awk'. * Arrays of Arrays:: True multidimensional arrays. * Arrays Summary:: Summary of arrays. -File: gawk.info, Node: Array Basics, Next: Delete, Up: Arrays +File: gawk.info, Node: Array Basics, Next: Numeric Array Subscripts, Up: Arrays 8.1 The Basics of Arrays ======================== @@ -10721,8 +10826,8 @@ program. Arrays in `awk' superficially resemble arrays in other programming languages, but there are fundamental differences. In `awk', it isn't necessary to specify the size of an array before starting to use it. -Additionally, any number or string in `awk', not just consecutive -integers, may be used as an array index. +Additionally, any number or string, not just consecutive integers, may +be used as an array index. In most other languages, arrays must be "declared" before use, including a specification of how many elements or components they @@ -10901,14 +11006,14 @@ encountering repeated numbers, gaps, or lines that don't begin with a number: { - if ($1 > max) - max = $1 - arr[$1] = $0 + if ($1 > max) + max = $1 + arr[$1] = $0 } END { - for (x = 1; x <= max; x++) - print arr[x] + for (x = 1; x <= max; x++) + print arr[x] } The first rule keeps track of the largest line number seen so far; @@ -10936,9 +11041,9 @@ overrides the others. Gaps in the line numbers can be handled with an easy improvement to the program's `END' rule, as follows: END { - for (x = 1; x <= max; x++) - if (x in arr) - print arr[x] + for (x = 1; x <= max; x++) + if (x in arr) + print arr[x] } @@ -10956,7 +11061,7 @@ lowest index up to the highest. This technique won't do the job in has a special kind of `for' statement for scanning an array: for (VAR in ARRAY) - BODY + BODY This loop executes BODY once for each index in ARRAY that the program has previously used, with the variable VAR set to that index. @@ -11013,7 +11118,7 @@ all `awk' versions do so. Consider this program, named `loopcheck.awk': } } - Here is what happens when run with `gawk': + Here is what happens when run with `gawk' (and `mawk'): $ gawk -f loopcheck.awk -| here @@ -11116,7 +11221,8 @@ available: to run. Changing `PROCINFO["sorted_in"]' in the loop body does not affect the loop. For example: - $ gawk 'BEGIN { + $ gawk ' + > BEGIN { > a[4] = 4 > a[3] = 3 > for (i in a) @@ -11124,7 +11230,8 @@ affect the loop. For example: > }' -| 4 4 -| 3 3 - $ gawk 'BEGIN { + $ gawk ' + > BEGIN { > PROCINFO["sorted_in"] = "@ind_str_asc" > a[4] = 4 > a[3] = 3 @@ -11176,93 +11283,15 @@ ordering when the numeric values are equal ensures that `gawk' behaves consistently across different environments. -File: gawk.info, Node: Delete, Next: Numeric Array Subscripts, Prev: Array Basics, Up: Arrays - -8.2 The `delete' Statement -========================== - -To remove an individual element of an array, use the `delete' statement: - - delete ARRAY[INDEX-EXPRESSION] - - Once an array element has been deleted, any value the element once -had is no longer available. It is as if the element had never been -referred to or been given a value. The following is an example of -deleting elements in an array: - - for (i in frequencies) - delete frequencies[i] - -This example removes all the elements from the array `frequencies'. -Once an element is deleted, a subsequent `for' statement to scan the -array does not report that element and the `in' operator to check for -the presence of that element returns zero (i.e., false): - - delete foo[4] - if (4 in foo) - print "This will never be printed" - - It is important to note that deleting an element is _not_ the same -as assigning it a null value (the empty string, `""'). For example: - - foo[4] = "" - if (4 in foo) - print "This is printed, even though foo[4] is empty" - - It is not an error to delete an element that does not exist. -However, if `--lint' is provided on the command line (*note Options::), -`gawk' issues a warning message when an element that is not in the -array is deleted. - - All the elements of an array may be deleted with a single statement -by leaving off the subscript in the `delete' statement, as follows: - - delete ARRAY - - Using this version of the `delete' statement is about three times -more efficient than the equivalent loop that deletes each element one -at a time. - - NOTE: For many years, using `delete' without a subscript was a - `gawk' extension. As of September, 2012, it was accepted for - inclusion into the POSIX standard. See the Austin Group website - (http://austingroupbugs.net/view.php?id=544). This form of the - `delete' statement is also supported by BWK `awk' and `mawk', as - well as by a number of other implementations (*note Other - Versions::). - - The following statement provides a portable but nonobvious way to -clear out an array:(1) - - split("", array) - - The `split()' function (*note String Functions::) clears out the -target array first. This call asks it to split apart the null string. -Because there is no data to split out, the function simply clears the -array and then returns. - - CAUTION: Deleting an array does not change its type; you cannot - delete an array and then use the array's name as a scalar (i.e., a - regular variable). For example, the following does not work: - - a[1] = 3 - delete a - a = 3 - - ---------- Footnotes ---------- - - (1) Thanks to Michael Brennan for pointing this out. - - -File: gawk.info, Node: Numeric Array Subscripts, Next: Uninitialized Subscripts, Prev: Delete, Up: Arrays +File: gawk.info, Node: Numeric Array Subscripts, Next: Uninitialized Subscripts, Prev: Array Basics, Up: Arrays -8.3 Using Numbers to Subscript Arrays +8.2 Using Numbers to Subscript Arrays ===================================== An important aspect to remember about arrays is that _array subscripts are always strings_. When a numeric value is used as a subscript, it is converted to a string value before being used for subscripting -(*note Conversion::). This means that the value of the built-in +(*note Conversion::). This means that the value of the predefined variable `CONVFMT' can affect how your program accesses elements of an array. For example: @@ -11285,9 +11314,9 @@ two significant digits. This test fails, since `"12.15"' is different from `"12.153"'. According to the rules for conversions (*note Conversion::), integer -values are always converted to strings as integers, no matter what the -value of `CONVFMT' may happen to be. So the usual case of the -following works: +values always convert to strings as integers, no matter what the value +of `CONVFMT' may happen to be. So the usual case of the following +works: for (i = 1; i <= maxsub; i++) do something with array[i] @@ -11300,14 +11329,14 @@ example, that `array[17]', `array[021]', and `array[0x11]' all refer to the same element! As with many things in `awk', the majority of the time things work -as one would expect them to. But it is useful to have a precise +as you would expect them to. But it is useful to have a precise knowledge of the actual rules since they can sometimes have a subtle effect on your programs. -File: gawk.info, Node: Uninitialized Subscripts, Next: Multidimensional, Prev: Numeric Array Subscripts, Up: Arrays +File: gawk.info, Node: Uninitialized Subscripts, Next: Delete, Prev: Numeric Array Subscripts, Up: Arrays -8.4 Using Uninitialized Variables as Subscripts +8.3 Using Uninitialized Variables as Subscripts =============================================== Suppose it's necessary to write a program to print the input data in @@ -11353,7 +11382,86 @@ string as a subscript if `--lint' is provided on the command line (*note Options::). -File: gawk.info, Node: Multidimensional, Next: Arrays of Arrays, Prev: Uninitialized Subscripts, Up: Arrays +File: gawk.info, Node: Delete, Next: Multidimensional, Prev: Uninitialized Subscripts, Up: Arrays + +8.4 The `delete' Statement +========================== + +To remove an individual element of an array, use the `delete' statement: + + delete ARRAY[INDEX-EXPRESSION] + + Once an array element has been deleted, any value the element once +had is no longer available. It is as if the element had never been +referred to or been given a value. The following is an example of +deleting elements in an array: + + for (i in frequencies) + delete frequencies[i] + +This example removes all the elements from the array `frequencies'. +Once an element is deleted, a subsequent `for' statement to scan the +array does not report that element and the `in' operator to check for +the presence of that element returns zero (i.e., false): + + delete foo[4] + if (4 in foo) + print "This will never be printed" + + It is important to note that deleting an element is _not_ the same +as assigning it a null value (the empty string, `""'). For example: + + foo[4] = "" + if (4 in foo) + print "This is printed, even though foo[4] is empty" + + It is not an error to delete an element that does not exist. +However, if `--lint' is provided on the command line (*note Options::), +`gawk' issues a warning message when an element that is not in the +array is deleted. + + All the elements of an array may be deleted with a single statement +by leaving off the subscript in the `delete' statement, as follows: + + delete ARRAY + + Using this version of the `delete' statement is about three times +more efficient than the equivalent loop that deletes each element one +at a time. + + This form of the `delete' statement is also supported by BWK `awk' +and `mawk', as well as by a number of other implementations. + + NOTE: For many years, using `delete' without a subscript was a + common extension. In September, 2012, it was accepted for + inclusion into the POSIX standard. See the Austin Group website + (http://austingroupbugs.net/view.php?id=544). + + The following statement provides a portable but nonobvious way to +clear out an array:(1) + + split("", array) + + The `split()' function (*note String Functions::) clears out the +target array first. This call asks it to split apart the null string. +Because there is no data to split out, the function simply clears the +array and then returns. + + CAUTION: Deleting all the elements from an array does not change + its type; you cannot clear an array and then use the array's name + as a scalar (i.e., a regular variable). For example, the following + does not work: + + a[1] = 3 + delete a + a = 3 + + ---------- Footnotes ---------- + + (1) Thanks to Michael Brennan for pointing this out. + + +File: gawk.info, Node: Multidimensional, Next: Arrays of Arrays, Prev: Delete, Up: Arrays 8.5 Multidimensional Arrays =========================== @@ -11365,7 +11473,7 @@ File: gawk.info, Node: Multidimensional, Next: Arrays of Arrays, Prev: Uninit A multidimensional array is an array in which an element is identified by a sequence of indices instead of a single index. For example, a two-dimensional array requires two indices. The usual way -(in most languages, including `awk') to refer to an element of a +(in many languages, including `awk') to refer to an element of a two-dimensional array named `grid' is with `grid[X,Y]'. Multidimensional arrays are supported in `awk' through concatenation @@ -11506,8 +11614,9 @@ multidimensional subscript). So the following is valid in `gawk': Each subarray and the main array can be of different length. In fact, the elements of an array or its subarray do not all have to have the same type. This means that the main array and any of its subarrays -can be non-rectangular, or jagged in structure. One can assign a scalar -value to the index `4' of the main array `a': +can be non-rectangular, or jagged in structure. You can assign a scalar +value to the index `4' of the main array `a', even though `a[1]' is +itself an array and not a scalar: a[4] = "An element in a jagged array" @@ -11568,6 +11677,8 @@ an array element is itself an array: print array[i][j] } } + else + print array[i] } If the structure of a jagged array of arrays is known in advance, @@ -11798,8 +11909,9 @@ brackets ([ ]): user-defined function that can be used to obtain a random non-negative integer less than N: - function randint(n) { - return int(n * rand()) + function randint(n) + { + return int(n * rand()) } The multiplication produces a random number greater than zero and @@ -11816,8 +11928,7 @@ brackets ([ ]): # Roll 3 six-sided dice and # print total number of points. { - printf("%d points\n", - roll(6)+roll(6)+roll(6)) + printf("%d points\n", roll(6) + roll(6) + roll(6)) } CAUTION: In most `awk' implementations, including `gawk', @@ -11904,8 +12015,7 @@ with character indices, and not byte indices. In the following list, optional parameters are enclosed in square brackets ([ ]). Several functions perform string substitution; the full discussion is provided in the description of the `sub()' function, -which comes towards the end since the list is presented in alphabetic -order. +which comes towards the end since the list is presented alphabetically. Those functions that are specific to `gawk' are marked with a pound sign (`#'). They are not available in compatibility mode (*note @@ -11938,7 +12048,8 @@ Options::): When comparing strings, `IGNORECASE' affects the sorting (*note Array Sorting Functions::). If the SOURCE array contains subarrays as values (*note Arrays of Arrays::), they will come - last, after all scalar values. + last, after all scalar values. Subarrays are _not_ recursively + sorted. For example, if the contents of `a' are as follows: @@ -12041,7 +12152,10 @@ Options::): If FIND is not found, `index()' returns zero. - It is a fatal error to use a regexp constant for FIND. + With BWK `awk' and `gawk', it is a fatal error to use a regexp + constant for FIND. Other implementations allow it, simply + treating the regexp constant as an expression meaning `$0 ~ + /regexp/'. (d.c.). `length('[STRING]`)' Return the number of characters in STRING. If STRING is a number, @@ -12101,21 +12215,20 @@ Options::): `match()', the order is the same as for the `~' operator: `STRING ~ REGEXP'. - The `match()' function sets the built-in variable `RSTART' to the - index. It also sets the built-in variable `RLENGTH' to the length - in characters of the matched substring. If no match is found, - `RSTART' is set to zero, and `RLENGTH' to -1. + The `match()' function sets the predefined variable `RSTART' to + the index. It also sets the predefined variable `RLENGTH' to the + length in characters of the matched substring. If no match is + found, `RSTART' is set to zero, and `RLENGTH' to -1. For example: { - if ($1 == "FIND") - regex = $2 - else { - where = match($0, regex) - if (where != 0) - print "Match of", regex, "found at", - where, "in", $0 + if ($1 == "FIND") + regex = $2 + else { + where = match($0, regex) + if (where != 0) + print "Match of", regex, "found at", where, "in", $0 } } @@ -12184,7 +12297,7 @@ Options::): The `patsplit()' function splits strings into pieces in a manner similar to the way input lines are split into fields using `FPAT' - (*note Splitting By Content::. + (*note Splitting By Content::). Before splitting the string, `patsplit()' deletes any previously existing elements in the arrays ARRAY and SEPS. @@ -12195,15 +12308,14 @@ Options::): first piece is stored in `ARRAY[1]', the second piece in `ARRAY[2]', and so forth. The string value of the third argument, FIELDSEP, is a regexp describing where to split STRING (much as - `FS' can be a regexp describing where to split input records; - *note Regexp Field Splitting::). If FIELDSEP is omitted, the - value of `FS' is used. `split()' returns the number of elements - created. SEPS is a `gawk' extension with `SEPS[I]' being the - separator string between `ARRAY[I]' and `ARRAY[I+1]'. If FIELDSEP - is a single space then any leading whitespace goes into `SEPS[0]' - and any trailing whitespace goes into `SEPS[N]' where N is the - return value of `split()' (that is, the number of elements in - ARRAY). + `FS' can be a regexp describing where to split input records). If + FIELDSEP is omitted, the value of `FS' is used. `split()' returns + the number of elements created. SEPS is a `gawk' extension with + `SEPS[I]' being the separator string between `ARRAY[I]' and + `ARRAY[I+1]'. If FIELDSEP is a single space then any leading + whitespace goes into `SEPS[0]' and any trailing whitespace goes + into `SEPS[N]' where N is the return value of `split()' (that is, + the number of elements in ARRAY). The `split()' function splits strings into pieces in a manner similar to the way input lines are split into fields. For example: @@ -12409,6 +12521,17 @@ Options::): Nonalphabetic characters are left unchanged. For example, `toupper("MiXeD cAsE 123")' returns `"MIXED CASE 123"'. + Matching the Null String + + In `awk', the `*' operator can match the null string. This is +particularly important for the `sub()', `gsub()', and `gensub()' +functions. For example: + + $ echo abc | awk '{ gsub(/m*/, "X"); print }' + -| XaXbXcX + +Although this makes a certain amount of sense, it can be surprising. + ---------- Footnotes ---------- (1) Unless you use the `--non-decimal-data' option, which isn't @@ -12428,8 +12551,8 @@ File: gawk.info, Node: Gory Details, Up: String Functions 9.1.3.1 More About `\' and `&' with `sub()', `gsub()', and `gensub()' ..................................................................... - CAUTION: This section has been known to cause headaches. You - might want to skip it upon first reading. + CAUTION: This subsubsection has been reported to cause headaches. + You might want to skip it upon first reading. When using `sub()', `gsub()', or `gensub()', and trying to get literal backslashes and ampersands into the replacement text, you need @@ -12563,17 +12686,6 @@ Table 9.4: Escape Sequence Processing For `gensub()' and the special cases for `sub()' and `gsub()', we recommend the use of `gawk' and `gensub()' when you have to do substitutions. - Matching the Null String - - In `awk', the `*' operator can match the null string. This is -particularly important for the `sub()', `gsub()', and `gensub()' -functions. For example: - - $ echo abc | awk '{ gsub(/m*/, "X"); print }' - -| XaXbXcX - -Although this makes a certain amount of sense, it can be surprising. - ---------- Footnotes ---------- (1) This was rather naive of him, despite there being a note in this @@ -12623,11 +12735,10 @@ parameters are enclosed in square brackets ([ ]): function--`gawk' also buffers its output and the `fflush()' function forces `gawk' to flush its buffers. - `fflush()' was added to BWK `awk' in April of 1992. For two - decades, it was not part of the POSIX standard. As of December, - 2012, it was accepted for inclusion into the POSIX standard. See - the Austin Group website - (http://austingroupbugs.net/view.php?id=634). + Brian Kernighan added `fflush()' to his `awk' in April of 1992. + For two decades, it was a common extension. In December, 2012, it + was accepted for inclusion into the POSIX standard. See the + Austin Group website (http://austingroupbugs.net/view.php?id=634). POSIX standardizes `fflush()' as follows: If there is no argument, or if the argument is the null string (`""'), then `awk' flushes @@ -12814,7 +12925,7 @@ enclosed in square brackets ([ ]): If DATESPEC does not contain enough elements or if the resulting time is out of range, `mktime()' returns -1. -`strftime(' [FORMAT [`,' TIMESTAMP [`,' UTC-FLAG] ] ]`)' +`strftime('[FORMAT [`,' TIMESTAMP [`,' UTC-FLAG] ] ]`)' Format the time specified by TIMESTAMP based on the contents of the FORMAT string and return the result. It is similar to the function of the same name in ISO C. If UTC-FLAG is present and is @@ -13029,7 +13140,7 @@ to the standard output and interprets the current time according to the format specifiers in the string. For example: $ date '+Today is %A, %B %d, %Y.' - -| Today is Monday, May 05, 2014. + -| Today is Monday, September 22, 2014. Here is the `gawk' version of the `date' utility. It has a shell "wrapper" to handle the `-u' option, which requires that `date' run as @@ -13118,12 +13229,13 @@ a given value. Finally, two other common operations are to shift the bits left or right. For example, if you have a bit string `10111001' and you shift -it right by three bits, you end up with `00010111'.(1) If you start over -again with `10111001' and shift it left by three bits, you end up with -`11001000'. `gawk' provides built-in functions that implement the -bitwise operations just described. They are: +it right by three bits, you end up with `00010111'.(1) If you start +over again with `10111001' and shift it left by three bits, you end up +with `11001000'. The following list describes `gawk''s built-in +functions that implement the bitwise operations. Optional parameters +are enclosed in square brackets ([ ]): -``and(V1, V2' [`,' ...]`)'' +``and('V1`,' V2 [`,' ...]`)'' Return the bitwise AND of the arguments. There must be at least two. @@ -13133,13 +13245,13 @@ bitwise operations just described. They are: ``lshift(VAL, COUNT)'' Return the value of VAL, shifted left by COUNT bits. -``or(V1, V2' [`,' ...]`)'' +``or('V1`,' V2 [`,' ...]`)'' Return the bitwise OR of the arguments. There must be at least two. ``rshift(VAL, COUNT)'' Return the value of VAL, shifted right by COUNT bits. -``xor(V1, V2' [`,' ...]`)'' +``xor('V1`,' V2 [`,' ...]`)'' Return the bitwise XOR of the arguments. There must be at least two. @@ -13214,7 +13326,7 @@ Nondecimal-numbers::), and then demonstrates the results of the (1) This example shows that 0's come in on the left side. For `gawk', this is always true, but in some languages, it's possible to -have the left side fill with 1's. Caveat emptor. +have the left side fill with 1's. File: gawk.info, Node: Type Functions, Next: I18N Functions, Prev: Bitwise Functions, Up: Built-in @@ -13224,7 +13336,7 @@ File: gawk.info, Node: Type Functions, Next: I18N Functions, Prev: Bitwise Fu `gawk' provides a single function that lets you distinguish an array from a scalar variable. This is necessary for writing code that -traverses every element of an array of arrays. (*note Arrays of +traverses every element of an array of arrays (*note Arrays of Arrays::). `isarray(X)' @@ -13236,12 +13348,12 @@ itself an array or not. The second is inside the body of a user-defined function (not discussed yet; *note User-defined::), to test if a parameter is an array or not. - Note, however, that using `isarray()' at the global level to test -variables makes no sense. Since you are the one writing the program, you -are supposed to know if your variables are arrays or not. And in fact, -due to the way `gawk' works, if you pass the name of a variable that -has not been previously used to `isarray()', `gawk' will end up turning -it into a scalar. + NOTE: Using `isarray()' at the global level to test variables + makes no sense. Since you are the one writing the program, you are + supposed to know if your variables are arrays or not. And in fact, + due to the way `gawk' works, if you pass the name of a variable + that has not been previously used to `isarray()', `gawk' ends up + turning it into a scalar. File: gawk.info, Node: I18N Functions, Prev: Type Functions, Up: Built-in @@ -13337,7 +13449,7 @@ call. A function cannot have two parameters with the same name, nor may it have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters cannot -have the same name as one of the special built-in variables (*note +have the same name as one of the special predefined variables (*note Built-in Variables::). Not all versions of `awk' enforce this restriction. @@ -13452,7 +13564,7 @@ extra whitespace signifies the start of the local variable list): function delarray(a, i) { for (i in a) - delete a[i] + delete a[i] } When working with arrays, it is often necessary to delete all the @@ -13460,8 +13572,8 @@ elements in an array and start over with a new list of elements (*note Delete::). Instead of having to repeat this loop everywhere that you need to clear out an array, your program can just call `delarray'. (This guarantees portability. The use of `delete ARRAY' to delete the -contents of an entire array is a recent(1) addition to the POSIX -standard.) +contents of an entire array is a relatively recent(1) addition to the +POSIX standard.) The following is an example of a recursive function. It takes a string as an input parameter and returns the string in backwards order. @@ -13484,7 +13596,7 @@ way: > gawk -e '{ print rev($0) }' -f rev.awk -| !cinaP t'noD - The C `ctime()' function takes a timestamp and returns it in a + The C `ctime()' function takes a timestamp and returns it as a string, formatted in a well-known fashion. The following example uses the built-in `strftime()' function (*note Time Functions::) to create an `awk' version of `ctime()': @@ -13495,12 +13607,18 @@ an `awk' version of `ctime()': function ctime(ts, format) { - format = PROCINFO["strftime"] + format = "%a %b %e %H:%M:%S %Z %Y" + if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) } + You might think that `ctime()' could use `PROCINFO["strftime"]' for +its format string. That would be a mistake, since `ctime()' is supposed +to return the time formatted in a standard fashion, and user-level code +could have changed `PROCINFO["strftime"]'. + ---------- Footnotes ---------- (1) Late in 2012. @@ -14042,7 +14160,7 @@ mechanism allows you to sort arbitrary data in an arbitrary fashion. # quicksort_swap --- helper function for quicksort, should really be inline - function quicksort_swap(data, i, j, temp) + function quicksort_swap(data, i, j, temp) { temp = data[i] data[i] = data[j] @@ -14145,6 +14263,63 @@ names of the two comparison functions: -| sort: <87.1 93.4 95.6 100.0> -| rsort: <100.0 95.6 93.4 87.1> + Another example where indirect functions calls are useful can be +found in processing arrays. *note Walking Arrays::, presented a simple +function for "walking" an array of arrays. That function simply +printed the name and value of each scalar array element. However, it is +easy to generalize that function, by passing in the name of a function +to call when walking an array. The modified function looks like this: + + function process_array(arr, name, process, do_arrays, i, new_name) + { + for (i in arr) { + new_name = (name "[" i "]") + if (isarray(arr[i])) { + if (do_arrays) + @process(new_name, arr[i]) + process_array(arr[i], new_name, process, do_arrays) + } else + @process(new_name, arr[i]) + } + } + + The arguments are as follows: + +`arr' + The array. + +`name' + The name of the array (a string). + +`process' + The name of the function to call. + +`do_arrays' + If this is true, the function can handle elements that are + subarrays. + + If subarrays are to be processed, that is done before walking them +further. + + When run with the following scaffolding, the function produces the +same results as does the earlier `walk_array()' function: + + BEGIN { + a[1] = 1 + a[2][1] = 21 + a[2][2] = 22 + a[3] = 3 + a[4][1][1] = 411 + a[4][2] = 42 + + process_array(a, "a", "do_print", 0) + } + + function do_print(name, element) + { + printf "%s = %s\n", name, element + } + Remember that you must supply a leading `@' in front of an indirect function call. @@ -14177,11 +14352,12 @@ File: gawk.info, Node: Functions Summary, Prev: Indirect Calls, Up: Functions functions. * POSIX `awk' provides three kinds of built-in functions: numeric, - string, and I/O. `gawk' provides functions that work with values - representing time, do bit manipulation, sort arrays, and - internationalize and localize programs. `gawk' also provides - several extensions to some of standard functions, typically in the - form of additional arguments. + string, and I/O. `gawk' provides functions that sort arrays, work + with values representing time, do bit manipulation, determine + variable type (array vs. scalar), and internationalize and + localize programs. `gawk' also provides several extensions to + some of standard functions, typically in the form of additional + arguments. * Functions accept zero or more arguments and return a value. The expressions that provide the argument values are completely @@ -14356,7 +14532,7 @@ to start that variable's name with a capital letter--for example, `getopt()''s `Opterr' and `Optind' variables (*note Getopt Function::). The leading capital letter indicates that it is global, while the fact that the variable name is not all capital letters indicates that the -variable is not one of `awk''s built-in variables, such as `FS'. +variable is not one of `awk''s predefined variables, such as `FS'. It is also important that _all_ variables in library functions that do not need to save state are, in fact, declared local.(2) If this is @@ -14366,8 +14542,9 @@ program, leading to bugs that are very difficult to track down: function lib_func(x, y, l1, l2) { ... - USE VARIABLE some_var # some_var should be local - ... # but is not by oversight + # some_var should be local but by oversight is not + USE VARIABLE some_var + ... } A different convention, common in the Tcl community, is to use a @@ -14416,6 +14593,7 @@ programming use. * Join Function:: A function to join an array into a string. * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the shell. File: gawk.info, Node: Strtonum Function, Next: Assert Function, Up: General Functions @@ -14475,7 +14653,7 @@ versions of `awk': # a[5] = "123.45" # a[6] = "1.e3" # a[7] = "1.32" - # a[7] = "1.32E2" + # a[8] = "1.32E2" # # for (i = 1; i in a; i++) # print a[i], strtonum(a[i]), mystrtonum(a[i]) @@ -14484,9 +14662,11 @@ versions of `awk': The function first looks for C-style octal numbers (base 8). If the input string matches a regular expression describing octal numbers, then `mystrtonum()' loops through each character in the string. It -sets `k' to the index in `"01234567"' of the current octal digit. -Since the return value is one-based, the `k--' adjusts `k' so it can be -used in computing the return value. +sets `k' to the index in `"1234567"' of the current octal digit. The +return value will either be the same number as the digit, or zero if +the character is not there, which will be true for a `0'. This is +safe, since the regexp test in the `if' ensures that only octal values +are converted. Similar logic applies to the code that checks for and converts a hexadecimal value, which starts with `0x' or `0X'. The use of @@ -14512,7 +14692,7 @@ condition or set of conditions is true. Before proceeding with a particular computation, you make a statement about what you believe to be the case. Such a statement is known as an "assertion". The C language provides an `<assert.h>' header file and corresponding -`assert()' macro that the programmer can use to make assertions. If an +`assert()' macro that a programmer can use to make assertions. If an assertion fails, the `assert()' macro arranges to print a diagnostic message describing the condition that should have been true but was not, and then it kills the program. In C, using `assert()' looks this: @@ -14852,7 +15032,7 @@ current time formatted in the same way as the `date' utility: now = systime() # return date(1)-style output - ret = strftime(PROCINFO["strftime"], now) + ret = strftime("%a %b %e %H:%M:%S %Z %Y", now) # clear out target array delete time @@ -14889,7 +15069,7 @@ the `getlocaltime()' function would have allowed the user to supply an optional timestamp value to use instead of the current time. -File: gawk.info, Node: Readfile Function, Prev: Getlocaltime Function, Up: General Functions +File: gawk.info, Node: Readfile Function, Next: Shell Quoting, Prev: Getlocaltime Function, Up: General Functions 10.2.8 Reading A Whole File At Once ----------------------------------- @@ -14948,6 +15128,61 @@ string. Thus calling code may use something like: This tests the result to see if it is empty or not. An equivalent test would be `contents == ""'. + *Note Extension Sample Readfile::, for an extension function that +also reads an entire file into memory. + + +File: gawk.info, Node: Shell Quoting, Prev: Readfile Function, Up: General Functions + +10.2.9 Quoting Strings to Pass to The Shell +------------------------------------------- + +Michael Brennan offers the following programming pattern, which he uses +frequently: + + #! /bin/sh + + awkp=' + ... + ' + + INPUT_PROGRAM | awk "$awkp" | /bin/sh + + For example, a program of his named `flac-edit' has this form: + + $ flac-edit -song="Whoope! That's Great" file.flac + + It generates the following output, which is to be piped to the shell +(`/bin/sh'): + + chmod +w file.flac + metaflac --remove-tag=TITLE file.flac + LANG=en_US.88591 metaflac --set-tag=TITLE='Whoope! That'"'"'s Great' file.flac + chmod -w file.flac + + Note the need for shell quoting. The function `shell_quote()' does +it. `SINGLE' is the one-character string `"'"' and `QSINGLE' is the +three-character string `"\"'\""'. + + # shell_quote --- quote an argument for passing to the shell + + function shell_quote(s, # parameter + SINGLE, QSINGLE, i, X, n, ret) # locals + { + if (s == "") + return "\"\"" + + SINGLE = "\x27" # single quote + QSINGLE = "\"\x27\"" + n = split(s, X, SINGLE) + + ret = SINGLE X[1] SINGLE + for (i = 2; i <= n; i++) + ret = ret QSINGLE SINGLE X[i] SINGLE + + return ret + } + File: gawk.info, Node: Data File Management, Next: Getopt Function, Prev: General Functions, Up: Library Functions @@ -14997,15 +15232,14 @@ does so _portably_; this works with any implementation of `awk': # that each take the name of the file being started or # finished, respectively. - FILENAME != _oldfilename \ - { + FILENAME != _oldfilename { if (_oldfilename != "") endfile(_oldfilename) _oldfilename = FILENAME beginfile(FILENAME) } - END { endfile(FILENAME) } + END { endfile(FILENAME) } This file must be loaded before the user's "main" program, so that the rule it supplies is executed first. @@ -15043,7 +15277,7 @@ solves the problem: beginfile(FILENAME) } - END { endfile(_filename_) } + END { endfile(_filename_) } *note Wc Program::, shows how this library function can be used and how it simplifies writing the main program. @@ -15096,15 +15330,12 @@ over with it from the top. For lack of a better name, we'll call it nextfile } - This code relies on the `ARGIND' variable (*note Auto-set::), which -is specific to `gawk'. If you are not using `gawk', you can use ideas -presented in *note Filetrans Function::, to either update `ARGIND' on -your own or modify this code as appropriate. - - The `rewind()' function also relies on the `nextfile' keyword (*note -Nextfile Statement::). Because of this, you should not call it from an -`ENDFILE' rule. (This isn't necessary anyway, since as soon as an -`ENDFILE' rule finishes `gawk' goes to the next file!) + The `rewind()' function relies on the `ARGIND' variable (*note +Auto-set::), which is specific to `gawk'. It also relies on the +`nextfile' keyword (*note Nextfile Statement::). Because of this, you +should not call it from an `ENDFILE' rule. (This isn't necessary +anyway, since as soon as an `ENDFILE' rule finishes `gawk' goes to the +next file!) File: gawk.info, Node: File Checking, Next: Empty Files, Prev: Rewind Function, Up: Data File Management @@ -15121,7 +15352,7 @@ following program to your `awk' program: BEGIN { for (i = 1; i < ARGC; i++) { - if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/ \ + if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \ || ARGV[i] == "-" || ARGV[i] == "/dev/stdin") continue # assignment or standard input else if ((getline junk < ARGV[i]) < 0) # unreadable @@ -15135,6 +15366,10 @@ following program to your `awk' program: element from `ARGV' with `delete' skips the file (since it's no longer in the list). See also *note ARGC and ARGV::. + The regular expression check purposely does not use character classes +such as `[:alpha:]' and `[:alnum:]' (*note Bracket Expressions::) since +`awk' variable names only allow the English letters. + ---------- Footnotes ---------- (1) The `BEGINFILE' special pattern (*note BEGINFILE/ENDFILE::) @@ -15213,7 +15448,7 @@ programming with a library file does the trick: function disable_assigns(argc, argv, i) { for (i = 1; i < argc; i++) - if (argv[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/) + if (argv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/) argv[i] = ("./" argv[i]) } @@ -15513,10 +15748,14 @@ result of two sample runs of the test program: In both runs, the first `--' terminates the arguments to `awk', so that it does not try to interpret the `-a', etc., as its own options. - NOTE: After `getopt()' is through, it is the responsibility of the - user level code to clear out all the elements of `ARGV' from 1 to - `Optind', so that `awk' does not try to process the command-line - options as file names. + NOTE: After `getopt()' is through, user level code must clear out + all the elements of `ARGV' from 1 to `Optind', so that `awk' does + not try to process the command-line options as file names. + + Using `#!' with the `-E' option may help avoid conflicts between +your program's options and `gawk''s options, since `-E' causes `gawk' +to abandon processing of further options (*note Executable Scripts::, +and *note Options::). Several of the sample programs presented in *note Sample Programs::, use `getopt()' to process their arguments. @@ -15675,8 +15914,8 @@ corresponding to the C functions of the same names: routine, we have chosen to put it in `/usr/local/libexec/awk'; however, you might want it to be in a different directory on your system. - The function `_pw_init()' keeps three copies of the user information -in three associative arrays. The arrays are indexed by username + The function `_pw_init()' fills three copies of the user information +into three associative arrays. The arrays are indexed by username (`_pw_byname'), by user ID number (`_pw_byuid'), and by order of occurrence (`_pw_bycount'). The variable `_pw_inited' is used for efficiency, since `_pw_init()' needs to be called only once. @@ -15686,13 +15925,10 @@ efficiency, since `_pw_init()' needs to be called only once. in the variable `using_fw' whether field splitting with `FIELDWIDTHS' is in effect or not. Doing so is necessary, since these functions could be called from anywhere within a user's program, and the user may -have his or her own way of splitting records and fields. - - The `using_fw' variable checks `PROCINFO["FS"]', which is -`"FIELDWIDTHS"' if field splitting is being done with `FIELDWIDTHS'. -This makes it possible to restore the correct field-splitting mechanism -later. The test can only be true for `gawk'. It is false if using -`FS' or `FPAT', or on some other `awk' implementation. +have his or her own way of splitting records and fields. This makes it +possible to restore the correct field-splitting mechanism later. The +test can only be true for `gawk'. It is false if using `FS' or `FPAT', +or on some other `awk' implementation. The code that checks for using `FPAT', using `using_fpat' and `PROCINFO["FS"]', is similar. @@ -15888,8 +16124,7 @@ the same names: n = split($4, a, "[ \t]*,[ \t]*") for (i = 1; i <= n; i++) if (a[i] in _gr_groupsbyuser) - _gr_groupsbyuser[a[i]] = \ - _gr_groupsbyuser[a[i]] " " $1 + _gr_groupsbyuser[a[i]] = gr_groupsbyuser[a[i]] " " $1 else _gr_groupsbyuser[a[i]] = $1 @@ -16051,12 +16286,12 @@ value. Here is a main program to demonstrate: When run, the program produces the following output: $ gawk -f walk_array.awk - -| a[4][1][1] = 411 - -| a[4][2] = 42 -| a[1] = 1 -| a[2][1] = 21 -| a[2][2] = 22 -| a[3] = 3 + -| a[4][1][1] = 411 + -| a[4][2] = 42 File: gawk.info, Node: Library Functions Summary, Next: Library Exercises, Prev: Walking Arrays, Up: Library Functions @@ -16065,8 +16300,8 @@ File: gawk.info, Node: Library Functions Summary, Next: Library Exercises, Pr ============ * Reading programs is an excellent way to learn Good Programming. - The functions provided in this major node and the next are intended - to serve that purpose. + The functions and programs provided in this major node and the next + are intended to serve that purpose. * When writing general-purpose library functions, put some thought into how to name any global variables so that they won't conflict @@ -16257,18 +16492,13 @@ supplied: # # Requires getopt() and join() library functions - function usage( e1, e2) + function usage() { - e1 = "usage: cut [-f list] [-d c] [-s] [files...]" - e2 = "usage: cut [-c list] [files...]" - print e1 > "/dev/stderr" - print e2 > "/dev/stderr" + print("usage: cut [-f list] [-d c] [-s] [files...]") > "/dev/stderr" + print("usage: cut [-c list] [files...]") > "/dev/stderr" exit 1 } -The variables `e1' and `e2' are used so that the function fits nicely -on the screen. - Next comes a `BEGIN' rule that parses the command-line options. It sets `FS' to a single TAB character, because that is `cut''s default field separator. The rule then sets the output field separator to be the @@ -16511,7 +16741,7 @@ Function::). The program begins with a descriptive comment and then a `BEGIN' rule that processes the command-line arguments with `getopt()'. The `-i' (ignore case) option is particularly easy with `gawk'; we just use the -`IGNORECASE' built-in variable (*note Built-in Variables::): +`IGNORECASE' predefined variable (*note Built-in Variables::): # egrep.awk --- simulate egrep in awk # @@ -16670,17 +16900,13 @@ there are no matches, the exit status is one; otherwise it is zero: The `usage()' function prints a usage message in case of invalid options, and then exits: - function usage( e) + function usage() { - e = "Usage: egrep [-csvil] [-e pat] [files ...]" - e = e "\n\tegrep [-csvil] pat [files ...]" - print e > "/dev/stderr" + print("Usage: egrep [-csvil] [-e pat] [files ...]") > "/dev/stderr" + print("\n\tegrep [-csvil] pat [files ...]") > "/dev/stderr" exit 1 } - The variable `e' is used so that the function fits nicely on the -printed page. - ---------- Footnotes ---------- (1) It also introduces a subtle bug; if a match happens, we output @@ -16731,26 +16957,22 @@ and the group numbers: printf("uid=%d", uid) pw = getpwuid(uid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (euid != uid) { printf(" euid=%d", euid) pw = getpwuid(euid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) } printf(" gid=%d", gid) pw = getgrgid(gid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (egid != gid) { printf(" egid=%d", egid) pw = getgrgid(egid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) } for (i = 1; ("group" i) in PROCINFO; i++) { @@ -16759,8 +16981,7 @@ and the group numbers: group = PROCINFO["group" i] printf("%d", group) pw = getgrgid(group) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (("group" (i+1)) in PROCINFO) printf(",") } @@ -16770,8 +16991,10 @@ and the group numbers: function pr_first_field(str, a) { - split(str, a, ":") - printf("(%s)", a[1]) + if (str != "") { + split(str, a, ":") + printf("(%s)", a[1]) + } } The test in the `for' loop is worth noting. Any supplementary @@ -16789,8 +17012,9 @@ then the condition is false the first time it's tested, and the loop body never executes. The `pr_first_field()' function simply isolates out some code that -is used repeatedly, making the whole program slightly shorter and -cleaner. +is used repeatedly, making the whole program shorter and cleaner. In +particular, moving the check for the empty string into this function +saves several lines of code. File: gawk.info, Node: Split Program, Next: Tee Program, Prev: Id Program, Up: Clones @@ -16881,15 +17105,12 @@ moves to the next letter in the alphabet and `s2' starts over again at The `usage()' function simply prints an error message and exits: - function usage( e) + function usage() { - e = "usage: split [-num] [file] [outname]" - print e > "/dev/stderr" + print("usage: split [-num] [file] [outname]") > "/dev/stderr" exit 1 } -The variable `e' is used so that the function fits nicely on the screen. - This program is a bit sloppy; it relies on `awk' to automatically close the last file instead of doing it in an `END' rule. It also assumes that letters are contiguous in the character set, which isn't @@ -17002,10 +17223,10 @@ usage is as follows: The options for `uniq' are: `-d' - Print only repeated lines. + Print only repeated (duplicated) lines. `-u' - Print only nonrepeated lines. + Print only nonrepeated (unique) lines. `-c' Count lines. This option overrides `-d' and `-u'. Both repeated @@ -17055,10 +17276,9 @@ standard output, `/dev/stdout': # # Requires getopt() and join() library functions - function usage( e) + function usage() { - e = "Usage: uniq [-udc [-n]] [+n] [ in [ out ]]" - print e > "/dev/stderr" + print("Usage: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr" exit 1 } @@ -17112,16 +17332,18 @@ standard output, `/dev/stdout': The following function, `are_equal()', compares the current line, `$0', to the previous line, `last'. It handles skipping fields and characters. If no field count and no character count are specified, -`are_equal()' simply returns one or zero depending upon the result of a -simple string comparison of `last' and `$0'. Otherwise, things get more -complicated. If fields have to be skipped, each line is broken into an -array using `split()' (*note String Functions::); the desired fields -are then joined back into a line using `join()'. The joined lines are -stored in `clast' and `cline'. If no fields are skipped, `clast' and -`cline' are set to `last' and `$0', respectively. Finally, if -characters are skipped, `substr()' is used to strip off the leading -`charcount' characters in `clast' and `cline'. The two strings are -then compared and `are_equal()' returns the result: +`are_equal()' returns one or zero depending upon the result of a simple +string comparison of `last' and `$0'. + + Otherwise, things get more complicated. If fields have to be +skipped, each line is broken into an array using `split()' (*note +String Functions::); the desired fields are then joined back into a line +using `join()'. The joined lines are stored in `clast' and `cline'. +If no fields are skipped, `clast' and `cline' are set to `last' and +`$0', respectively. Finally, if characters are skipped, `substr()' is +used to strip off the leading `charcount' characters in `clast' and +`cline'. The two strings are then compared and `are_equal()' returns +the result: function are_equal( n, m, clast, cline, alast, aline) { @@ -17217,8 +17439,8 @@ one or more input files. Its usage is as follows: If no files are specified on the command line, `wc' reads its standard input. If there are multiple files, it also prints total -counts for all the files. The options and their meanings are shown in -the following list: +counts for all the files. The options and their meanings are as +follows: `-l' Count only lines. @@ -17574,17 +17796,17 @@ there are more characters in the "from" list than in the "to" list, the last character of the "to" list is used for the remaining characters in the "from" list. - Once upon a time, a user proposed that a transliteration function -should be added to `gawk'. The following program was written to prove -that character transliteration could be done with a user-level -function. This program is not as complete as the system `tr' utility -but it does most of the job. + Once upon a time, a user proposed adding a transliteration function +to `gawk'. The following program was written to prove that character +transliteration could be done with a user-level function. This program +is not as complete as the system `tr' utility but it does most of the +job. - The `translate' program demonstrates one of the few weaknesses of -standard `awk': dealing with individual characters is very painful, -requiring repeated use of the `substr()', `index()', and `gsub()' -built-in functions (*note String Functions::).(2) There are two -functions. The first, `stranslate()', takes three arguments: + The `translate' program was written long before `gawk' acquired the +ability to split each character in a string into separate array +elements. Thus, it makes repeated use of the `substr()', `index()', +and `gsub()' built-in functions (*note String Functions::). There are +two functions. The first, `stranslate()', takes three arguments: `from' A list of characters from which to translate. @@ -17601,10 +17823,10 @@ simple loop goes through `from', one character at a time. For each character in `from', if the character appears in `target', it is replaced with the corresponding `to' character. - The `translate()' function simply calls `stranslate()' using `$0' as -the target. The main program sets two global variables, `FROM' and -`TO', from the command line, and then changes `ARGV' so that `awk' -reads from the standard input. + The `translate()' function calls `stranslate()' using `$0' as the +target. The main program sets two global variables, `FROM' and `TO', +from the command line, and then changes `ARGV' so that `awk' reads from +the standard input. Finally, the processing rule simply calls `translate()' for each record: @@ -17681,9 +17903,6 @@ program. enclosed in square brackets (`[a-z]') and quoted, to prevent the shell from attempting a file name expansion. This is not a feature. - (2) This program was also written before `gawk' acquired the ability -to split each character in a string into separate array elements. - File: gawk.info, Node: Labels Program, Next: Word Sorting, Prev: Translate Program, Up: Miscellaneous Programs @@ -17709,12 +17928,12 @@ splits records at blank lines (*note Records::). It sets `MAXLINES' to Most of the work is done in the `printpage()' function. The label lines are stored sequentially in the `line' array. But they have to print horizontally; `line[1]' next to `line[6]', `line[2]' next to -`line[7]', and so on. Two loops are used to accomplish this. The -outer loop, controlled by `i', steps through every 10 lines of data; -this is each row of labels. The inner loop, controlled by `j', goes -through the lines within the row. As `j' goes from 0 to 4, `i+j' is -the `j'-th line in the row, and `i+j+5' is the entry next to it. The -output ends up looking something like this: +`line[7]', and so on. Two loops accomplish this. The outer loop, +controlled by `i', steps through every 10 lines of data; this is each +row of labels. The inner loop, controlled by `j', goes through the +lines within the row. As `j' goes from 0 to 4, `i+j' is the `j'-th +line in the row, and `i+j+5' is the entry next to it. The output ends +up looking something like this: line 1 line 6 line 2 line 7 @@ -17805,7 +18024,7 @@ a useful format. At first glance, a program like this would seem to do the job: - # Print list of word frequencies + # wordfreq-first-try.awk --- print list of word frequencies { for (i = 1; i <= NF; i++) @@ -17959,9 +18178,9 @@ Texinfo input file into separate files. This Info file is written in Texinfo (http://www.gnu.org/software/texinfo/), the GNU project's document formatting language. A single Texinfo source file can be used to -produce both printed and online documentation. The Texinfo language is -described fully, starting with *note (Texinfo)Top:: -texinfo,Texinfo--The GNU Documentation Format. +produce both printed documentation, with TeX, and online documentation. +(The Texinfo language is described fully, starting with *note +(Texinfo)Top:: texinfo,Texinfo--The GNU Documentation Format.) For our purposes, it is enough to know three things about Texinfo input files: @@ -18023,13 +18242,11 @@ upper- and lowercase letters in the directives won't matter. given (`NF' is at least three) and also checking that the command exits with a zero exit status, signifying OK: - # extract.awk --- extract files and run programs - # from texinfo files + # extract.awk --- extract files and run programs from texinfo files BEGIN { IGNORECASE = 1 } - /^@c(omment)?[ \t]+system/ \ - { + /^@c(omment)?[ \t]+system/ { if (NF < 3) { e = ("extract: " FILENAME ":" FNR) e = (e ": badly formed `system' line") @@ -18077,8 +18294,7 @@ with the value of `SUBSEP' (*note Multidimensional::), to rejoin the pieces back into a single line. That line is then printed to the output file: - /^@c(omment)?[ \t]+file/ \ - { + /^@c(omment)?[ \t]+file/ { if (NF != 3) { e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") print e > "/dev/stderr" @@ -18132,7 +18348,7 @@ closing the open file: function unexpected_eof() { printf("extract: %s:%d: unexpected EOF or error\n", - FILENAME, FNR) > "/dev/stderr" + FILENAME, FNR) > "/dev/stderr" exit 1 } @@ -18154,7 +18370,7 @@ pipeline of commands. While `sed' is a complicated program in its own right, its most common use is to perform global substitutions in the middle of a pipeline: - command1 < orig.data | sed 's/old/new/g' | command2 > result + COMMAND1 < orig.data | sed 's/old/new/g' | COMMAND2 > result Here, `s/old/new/g' tells `sed' to look for the regexp `old' on each input line and globally replace it with the text `new', i.e., all the @@ -18341,8 +18557,8 @@ arguments are supplied, then the first nonoption argument should be the `awk' program. If there are no command-line arguments left, `igawk' prints an error message and exits. Otherwise, the first argument is appended to `program'. In any case, after the arguments have been -processed, `program' contains the complete text of the original `awk' -program. +processed, the shell variable `program' contains the complete text of +the original `awk' program. The program is as follows: @@ -18588,7 +18804,7 @@ and it is frequently easier to do certain kinds of string and argument manipulation using the shell than it is in `awk'. Finally, `igawk' shows that it is not always necessary to add new -features to a program; they can often be layered on top. +features to a program; they can often be layered on top.(3) ---------- Footnotes ---------- @@ -18597,7 +18813,10 @@ book. We provide some minimal explanations, but see a good shell programming book if you wish to understand things in more depth. (2) On some very old versions of `awk', the test `getline junk < t' -can loop forever if the file exists but is empty. Caveat emptor. +can loop forever if the file exists but is empty. + + (3) `gawk' does `@include' processing itself in order to support the +use of `awk' programs as Web CGI scripts. File: gawk.info, Node: Anagram Program, Next: Signature Program, Prev: Igawk Program, Up: Miscellaneous Programs @@ -18610,12 +18829,11 @@ word list (such as `/usr/share/dict/words' on many GNU/Linux systems). One word is an anagram of another if both words contain the same letters (for example, "babbling" and "blabbing"). - An elegant algorithm is presented in Column 2, Problem C of Jon -Bentley's `Programming Pearls', second edition. The idea is to give -words that are anagrams a common signature, sort all the words together -by their signature, and then print them. Dr. Bentley observes that -taking the letters in each word and sorting them produces that common -signature. + Column 2, Problem C of Jon Bentley's `Programming Pearls', second +edition, presents an elegant algorithm. The idea is to give words that +are anagrams a common signature, sort all the words together by their +signature, and then print them. Dr. Bentley observes that taking the +letters in each word and sorting them produces that common signature. The following program uses arrays of arrays to bring together words with the same signature and array sorting to print the words in sorted @@ -18724,9 +18942,9 @@ File: gawk.info, Node: Programs Summary, Next: Programs Exercises, Prev: Misc 11.4 Summary ============ - * The functions provided in this major node and the previous one - continue on the theme that reading programs is an excellent way to - learn Good Programming. + * The programs provided in this major node continue on the theme + that reading programs is an excellent way to learn Good + Programming. * Using `#!' to make `awk' programs directly runnable makes them easier to use. Otherwise, invoke the program using `awk -f ...'. @@ -18755,7 +18973,7 @@ File: gawk.info, Node: Programs Exercises, Prev: Programs Summary, Up: Sample ============== 1. Rewrite `cut.awk' (*note Cut Program::) using `split()' with `""' - as the seperator. + as the separator. 2. In *note Egrep Program::, we mentioned that `egrep -i' could be simulated in versions of `awk' without `IGNORECASE' by using @@ -18779,7 +18997,7 @@ File: gawk.info, Node: Programs Exercises, Prev: Programs Summary, Up: Sample that can be in one of a set number of stable conditions depending on its previous condition and on the present values of its inputs."(1) Brian Kernighan suggests that "an alternative approach - to state mechines is to just read the input into an array, then + to state machines is to just read the input into an array, then use indexing. It's almost always easier code, and for most inputs where you would use this, just as fast." Rewrite the logic to follow this suggestion. @@ -18903,11 +19121,10 @@ File: gawk.info, Node: Nondecimal Data, Next: Array Sorting, Up: Advanced Fea =================================== If you run `gawk' with the `--non-decimal-data' option, you can have -nondecimal constants in your input data: +nondecimal values in your input data: $ echo 0123 123 0x123 | - > gawk --non-decimal-data '{ printf "%d, %d, %d\n", - > $1, $2, $3 }' + > gawk --non-decimal-data '{ printf "%d, %d, %d\n", $1, $2, $3 }' -| 83, 123, 291 For this feature to work, write your program so that `gawk' treats @@ -18938,6 +19155,8 @@ request it. programs easier to write and easier to read, and leads to less surprising results. + This option may disappear in a future version of `gawk'. + File: gawk.info, Node: Array Sorting, Next: Two-way I/O, Prev: Nondecimal Data, Up: Advanced Features @@ -18976,7 +19195,7 @@ pre-defined values to `PROCINFO["sorted_in"]' in order to control the order in which `gawk' traverses an array during a `for' loop. In addition, the value of `PROCINFO["sorted_in"]' can be a function -name. This lets you traverse an array based on any custom criterion. +name.(1) This lets you traverse an array based on any custom criterion. The array elements are ordered according to the return value of this function. The comparison function should be defined with at least four arguments: @@ -19091,7 +19310,7 @@ of the previous functions: according to login name. The following program sorts records by a specific field position and can be used for this purpose: - # sort.awk --- simple program to sort by field position + # passwd-sort.awk --- simple program to sort by field position # field position is specified by the global variable POS function cmp_field(i1, v1, i2, v2) @@ -19143,13 +19362,14 @@ seemingly ordered data: elements compare equal. This is usually not a problem, but letting the tied elements come out in arbitrary order can be an issue, especially when comparing item values. The partial ordering of the equal elements -may change during the next loop traversal, if other elements are added -or removed from the array. One way to resolve ties when comparing -elements with otherwise equal values is to include the indices in the -comparison rules. Note that doing this may make the loop traversal -less efficient, so consider it only if necessary. The following -comparison functions force a deterministic order, and are based on the -fact that the (string) indices of two elements are never equal: +may change the next time the array is traversed, if other elements are +added or removed from the array. One way to resolve ties when +comparing elements with otherwise equal values is to include the +indices in the comparison rules. Note that doing this may make the +loop traversal less efficient, so consider it only if necessary. The +following comparison functions force a deterministic order, and are +based on the fact that the (string) indices of two elements are never +equal: function cmp_numeric(i1, v1, i2, v2) { @@ -19188,6 +19408,11 @@ array has been reported to add 15% to 20% overhead to the execution time of `awk' programs. For this reason, sorted array traversal is not the default. + ---------- Footnotes ---------- + + (1) This is why the predefined sorting orders start with an `@' +character, which cannot be part of an identifier. + File: gawk.info, Node: Array Sorting Functions, Prev: Controlling Array Traversal, Up: Array Sorting @@ -19274,7 +19499,7 @@ fill in the result array. Because `IGNORECASE' affects string comparisons, the value of `IGNORECASE' also affects sorting for both `asort()' and `asorti()'. Note also that the locale's sorting order does _not_ come into play; -comparisons are based on character values only.(1) Caveat Emptor. +comparisons are based on character values only.(1) ---------- Footnotes ---------- @@ -19400,7 +19625,7 @@ using regular pipes. (1) Michael Brennan suggests the use of `rand()' to generate unique file names. This is a valid point; nevertheless, temporary files remain -more difficult than two-way pipes. +more difficult to use than two-way pipes. (2) This is very different from the same operator in the C shell and in Bash. @@ -19411,11 +19636,11 @@ File: gawk.info, Node: TCP/IP Networking, Next: Profiling, Prev: Two-way I/O, 12.4 Using `gawk' for Network Programming ========================================= - `EMISTERED': + `EMRED': A host is a host from coast to coast, - and no-one can talk to host that's close, + and nobody talks to a host that's close, unless the host that isn't close - is busy hung or dead. + is busy, hung, or dead. -- Mike O'Brien (aka Mr. Protocol) In addition to being able to open a two-way pipeline to a coprocess on the same system (*note Two-way I/O::), it is possible to make a two-way @@ -19439,8 +19664,8 @@ NET-TYPE PROTOCOL The protocol to use over IP. This must be either `tcp', or `udp', - for a TCP or UDP IP connection, respectively. The use of TCP is - recommended for most applications. + for a TCP or UDP IP connection, respectively. TCP should be used + for most applications. LOCAL-PORT The local TCP or UDP port number to use. Use a port number of `0' @@ -19466,10 +19691,10 @@ REMOTE-PORT Consider the following very simple example: BEGIN { - Service = "/inet/tcp/0/localhost/daytime" - Service |& getline - print $0 - close(Service) + Service = "/inet/tcp/0/localhost/daytime" + Service |& getline + print $0 + close(Service) } This program reads the current date and time from the local system's @@ -19544,9 +19769,9 @@ First, the `awk' program: profiler on this program and data. (This example also illustrates that `awk' programmers sometimes get up very early in the morning to work.) - # gawk profile, created Thu Feb 27 05:16:21 2014 + # gawk profile, created Mon Sep 29 05:16:21 2014 - # BEGIN block(s) + # BEGIN rule(s) BEGIN { 1 print "First BEGIN rule" @@ -19573,7 +19798,7 @@ profiler on this program and data. (This example also illustrates that } } - # END block(s) + # END rule(s) END { 1 print "First END rule" @@ -19648,8 +19873,7 @@ output. They are as follows: you typed when you wrote it. This is because `gawk' creates the profiled version by "pretty printing" its internal representation of the program. The advantage to this is that `gawk' can produce a -standard representation. The disadvantage is that all source-code -comments are lost. Also, things such as: +standard representation. Also, things such as: /foo/ @@ -19659,7 +19883,7 @@ come out as: print $0 } -which is correct, but possibly surprising. +which is correct, but possibly unexpected. Besides creating profiles when a program has completed, `gawk' can produce a profile while it is running. This is useful if your `awk' @@ -19676,7 +19900,7 @@ The shell prints a job number and process ID number; in this case, $ kill -USR1 13992 As usual, the profiled version of the program is written to -`awkprof.out', or to a different file if one specified with the +`awkprof.out', or to a different file if one was specified with the `--profile' option. Along with the regular profile, as shown earlier, the profile file @@ -19711,6 +19935,22 @@ without any execution counts. NOTE: Once upon a time, the `--pretty-print' option would also run your program. This is is no longer the case. + There is a significant difference between the output created when +profiling, and that created when pretty-printing. Pretty-printed output +preserves the original comments that were in the program, although their +placement may not correspond exactly to their original locations in the +source code. + + However, as a deliberate design decision, profiling output _omits_ +the original program's comments. This allows you to focus on the +execution count data and helps you avoid the temptation to use the +profiler for pretty-printing. + + Additionally, pretty-printed output does not have the leading +indentation that the profiling output does. This makes it easy to +pretty-print your code once development is completed, and then use the +result as the final version of your program. + File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanced Features @@ -19720,7 +19960,8 @@ File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanc * The `--non-decimal-data' option causes `gawk' to treat octal- and hexadecimal-looking input data as octal and hexadecimal. This option should be used with caution or not at all; use of - `strtonum()' is preferable. + `strtonum()' is preferable. Note that this option may disappear + in a future version of `gawk'. * You can take over complete control of sorting in `for (INDX in ARRAY)' array traversal by setting `PROCINFO["sorted_in"]' to the @@ -19734,14 +19975,14 @@ File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanc `PROCINFO["sorted_in"]'. * You can use the `|&' operator to create a two-way pipe to a - co-process. You read from the co-process with `getline' and write + coprocess. You read from the coprocess with `getline' and write to it with `print' or `printf'. Use `close()' to close off the - co-process completely, or optionally, close off one side of the + coprocess completely, or optionally, close off one side of the two-way communications. - * By using special "file names" with the `|&' operator, you can open - a TCP/IP (or UDP/IP) connection to remote hosts in the Internet. - `gawk' supports both IPv4 an IPv6. + * By using special file names with the `|&' operator, you can open a + TCP/IP (or UDP/IP) connection to remote hosts in the Internet. + `gawk' supports both IPv4 and IPv6. * You can generate statement count profiles of your program. This can help you determine which parts of your program may be taking @@ -19902,7 +20143,7 @@ are: Character-type information (alphabetic, digit, upper- or lowercase, and so on) as well as character encoding. This information is accessed via the POSIX character classes in regular - expressions, such as `/[[:alnum:]]/' (*note Regexp Operators::). + expressions, such as `/[[:alnum:]]/' (*note Bracket Expressions::). `LC_MONETARY' Monetary information, such as the currency symbol, and whether the @@ -19970,8 +20211,8 @@ internationalization: Return the plural form used for NUMBER of the translation of STRING1 and STRING2 in text domain DOMAIN for locale category CATEGORY. STRING1 is the English singular variant of a message, - and STRING2 the English plural variant of the same message. The - default value for DOMAIN is the current value of `TEXTDOMAIN'. + and STRING2 is the English plural variant of the same message. + The default value for DOMAIN is the current value of `TEXTDOMAIN'. The default value for CATEGORY is `"LC_MESSAGES"'. The same remarks about argument order as for the `dcgettext()' @@ -20024,9 +20265,11 @@ outlined in *note Explaining gettext::, like so: one. This example would be better done with `dcngettext()': if (groggy) - message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") + message = dcngettext("%d customer disturbing me\n", + "%d customers disturbing me\n", "adminprog") else - message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") + message = dcngettext("enjoying %d customer\n", + "enjoying %d customers\n", "adminprog") printf(message, ncustomers) 4. During development, you might want to put the `.gmo' file in a @@ -20084,7 +20327,7 @@ marked and you've set (and perhaps bound) the text domain, it is time to produce translations. First, use the `--gen-pot' command-line option to create the initial `.pot' file: - $ gawk --gen-pot -f guide.awk > guide.pot + gawk --gen-pot -f guide.awk > guide.pot When run with `--gen-pot', `gawk' does not execute your program. Instead, it parses it as usual and prints all marked strings to @@ -20136,11 +20379,11 @@ example, `string' is the first argument and `length(string)' is the second: $ gawk 'BEGIN { - > string = "Dont Panic" + > string = "Don\47t Panic" > printf "%2$d characters live in \"%1$s\"\n", > string, length(string) > }' - -| 10 characters live in "Dont Panic" + -| 11 characters live in "Don't Panic" If present, positional specifiers come first in the format specification, before the flags, the field width, and/or the precision. @@ -20301,7 +20544,8 @@ Following are the translations: The next step is to make the directory to hold the binary message object file and then to create the `guide.mo' file. We pretend that -our file is to be used in the `en_US.UTF-8' locale. The directory +our file is to be used in the `en_US.UTF-8' locale, since we have to +use a locale name known to the C `gettext' routines. The directory layout shown here is standard for GNU `gettext' on GNU/Linux systems. Other versions of `gettext' may use a different layout: @@ -20310,7 +20554,7 @@ Other versions of `gettext' may use a different layout: The `msgfmt' utility does the conversion from human-readable `.po' file to machine-readable `.mo' file. By default, `msgfmt' creates a file named `messages'. This file must be renamed and placed in the -proper directory so that `gawk' can find it: +proper directory (using the `-o' option) so that `gawk' can find it: $ msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo @@ -20343,8 +20587,8 @@ File: gawk.info, Node: Gawk I18N, Next: I18N Summary, Prev: I18N Example, Up `gawk' itself has been internationalized using the GNU `gettext' package. (GNU `gettext' is described in complete detail in *note (GNU `gettext' utilities)Top:: gettext, GNU gettext tools.) As of this -writing, the latest version of GNU `gettext' is version 0.19.1 -(ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.1.tar.gz). +writing, the latest version of GNU `gettext' is version 0.19.3 +(ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.3.tar.gz). If a translation of `gawk''s messages exists, then `gawk' produces usage messages, warnings, and fatal errors in the local language. @@ -20429,7 +20673,7 @@ File: gawk.info, Node: Debugging Concepts, Next: Debugging Terms, Up: Debuggi --------------------------- (If you have used debuggers in other languages, you may want to skip -ahead to the next section on the specific features of the `awk' +ahead to the next section on the specific features of the `gawk' debugger.) Of course, a debugging program cannot remove bugs for you, since it @@ -20465,8 +20709,8 @@ functional program that you or someone else wrote). File: gawk.info, Node: Debugging Terms, Next: Awk Debugging, Prev: Debugging Concepts, Up: Debugging -14.1.2 Additional Debugging Concepts ------------------------------------- +14.1.2 Debugging Concepts +------------------------- Before diving in to the details, we need to introduce several important concepts that apply to just about all debuggers. The following list @@ -20558,13 +20802,13 @@ File: gawk.info, Node: Debugger Invocation, Next: Finding The Bug, Up: Sample 14.2.1 How to Start the Debugger -------------------------------- -Starting the debugger is almost exactly like running `gawk', except you -have to pass an additional option `--debug' or the corresponding short -option `-D'. The file(s) containing the program and any supporting -code are given on the command line as arguments to one or more `-f' -options. (`gawk' is not designed to debug command-line programs, only -programs contained in files.) In our case, we invoke the debugger like -this: +Starting the debugger is almost exactly like running `gawk' normally, +except you have to pass an additional option `--debug', or the +corresponding short option `-D'. The file(s) containing the program +and any supporting code are given on the command line as arguments to +one or more `-f' options. (`gawk' is not designed to debug command-line +programs, only programs contained in files.) In our case, we invoke +the debugger like this: $ gawk -D -f getopt.awk -f join.awk -f uniq.awk -1 inputfile @@ -20573,7 +20817,7 @@ users of GDB or similar debuggers should note that this syntax is slightly different from what they are used to. With the `gawk' debugger, you give the arguments for running the program in the command line to the debugger rather than as part of the `run' command at the -debugger prompt.) +debugger prompt.) The `-1' is an option to `uniq.awk'. Instead of immediately running the program on `inputfile', as `gawk' would ordinarily do, the debugger merely loads all the program source @@ -20721,9 +20965,9 @@ split into, so we try to look: This is kind of disappointing, though. All we found out is that there are five elements in `alast'; `m' and `aline' don't have values -yet since we are at line 68 but haven't executed it yet. This -information is useful enough (we now know that none of the words were -accidentally left out), but what if we want to see inside the array? +since we are at line 68 but haven't executed it yet. This information +is useful enough (we now know that none of the words were accidentally +left out), but what if we want to see inside the array? The first choice would be to use subscripts: @@ -20873,13 +21117,13 @@ controlling breakpoints are: `condition' N `"EXPRESSION"' Add a condition to existing breakpoint or watchpoint N. The - condition is an `awk' expression that the debugger evaluates - whenever the breakpoint or watchpoint is reached. If the condition - is true, then the debugger stops execution and prompts for a - command. Otherwise, the debugger continues executing the program. - If the condition expression is not specified, any existing - condition is removed; i.e., the breakpoint or watchpoint is made - unconditional. + condition is an `awk' expression _enclosed in double quotes_ that + the debugger evaluates whenever the breakpoint or watchpoint is + reached. If the condition is true, then the debugger stops + execution and prompts for a command. Otherwise, the debugger + continues executing the program. If the condition expression is + not specified, any existing condition is removed; i.e., the + breakpoint or watchpoint is made unconditional. `delete' [N1 N2 ...] [N-M] `d' [N1 N2 ...] [N-M] @@ -20998,9 +21242,9 @@ execution of the program than we saw in our earlier example: `until' [[FILENAME`:']N | FUNCTION] `u' [[FILENAME`:']N | FUNCTION] Without any argument, continue execution until a line past the - current line in current stack frame is reached. With an argument, - continue execution until the specified location is reached, or the - current stack frame returns. + current line in the current stack frame is reached. With an + argument, continue execution until the specified location is + reached, or the current stack frame returns. File: gawk.info, Node: Viewing And Changing Data, Next: Execution Stack, Prev: Debugger Execution Control, Up: List of Debugger Commands @@ -21047,9 +21291,9 @@ AWK STATEMENTS This prints the third field in the input record (if the specified field does not exist, it prints `Null field'). A variable can be - an array element, with the subscripts being constant values. To - print the contents of an array, prefix the name of the array with - the `@' symbol: + an array element, with the subscripts being constant string + values. To print the contents of an array, prefix the name of the + array with the `@' symbol: gawk> print @a @@ -21094,7 +21338,7 @@ AWK STATEMENTS File: gawk.info, Node: Execution Stack, Next: Debugger Info, Prev: Viewing And Changing Data, Up: List of Debugger Commands -14.3.4 Dealing with the Stack +14.3.4 Working with the Stack ----------------------------- Whenever you run a program which contains any function calls, `gawk' @@ -21106,11 +21350,13 @@ are: `backtrace' [COUNT] `bt' [COUNT] +`where' [COUNT] Print a backtrace of all function calls (stack frames), or innermost COUNT frames if COUNT > 0. Print the outermost COUNT frames if COUNT < 0. The backtrace displays the name and arguments to each function, the source file name, and the line - number. + number. The alias `where' for `backtrace' is provided for + long-time GDB users who may be used to that command. `down' [COUNT] Move COUNT (default 1) frames down the stack toward the innermost @@ -21147,7 +21393,7 @@ know: The value for WHAT should be one of the following: `args' - Arguments of the selected frame. + List arguments of the selected frame. `break' List all currently set breakpoints. @@ -21156,19 +21402,19 @@ know: List all items in the automatic display list. `frame' - Description of the selected stack frame. + Give a description of the selected stack frame. `functions' List all function definitions including source file names and line numbers. `locals' - Local variables of the selected frame. + List local variables of the selected frame. `source' - The name of the current source file. Each time the program - stops, the current source file is the file containing the - current instruction. When the debugger first starts, the + Print the name of the current source file. Each time the + program stops, the current source file is the file containing + the current instruction. When the debugger first starts, the current source file is the first file included via the `-f' option. The `list FILENAME:LINENO' command can be used at any time to change the current source. @@ -21316,7 +21562,7 @@ categories, as follows: or the file named FILENAME. The possible arguments to `list' are as follows: - `-' + `-' (Minus) Print lines before the lines last printed. `+' @@ -21387,8 +21633,8 @@ Variable name completion File: gawk.info, Node: Limitations, Next: Debugging Summary, Prev: Readline Support, Up: Debugger -14.5 Limitations and Future Plans -================================= +14.5 Limitations +================ We hope you find the `gawk' debugger useful and enjoyable to work with, but as with any program, especially in its early releases, it still has @@ -21427,10 +21673,6 @@ some limitations. A few which are worth being aware of are: * The `gawk' debugger only accepts source supplied with the `-f' option. - Look forward to a future release when these and other missing -features may be added, and of course feel free to try to add them -yourself! - File: gawk.info, Node: Debugging Summary, Prev: Limitations, Up: Debugger @@ -21467,8 +21709,7 @@ File: gawk.info, Node: Arbitrary Precision Arithmetic, Next: Dynamic Extension ************************************************************ This major node introduces some basic concepts relating to how -computers do arithmetic and briefly lists the features in `gawk' for -performing arbitrary precision floating point computations. It then +computers do arithmetic and defines some important terms. It then proceeds to describe floating-point arithmetic, which is what `awk' uses for all its computations, including a discussion of arbitrary precision floating point arithmetic, which is a feature available only @@ -21563,9 +21804,10 @@ Floating point arithmetic ranges. Integer values are usually either 32 or 64 bits in size. Single precision floating point values occupy 32 bits, whereas double precision floating point values occupy 64 bits. Floating point values are always -signed. The possible ranges of values are shown in the following table. +signed. The possible ranges of values are shown in *note +table-numeric-ranges::. -Numeric representation Miniumum value Maximum value +Numeric representation Minimum value Maximum value --------------------------------------------------------------------------- 32-bit signed integer -2,147,483,648 2,147,483,647 32-bit unsigned integer 0 4,294,967,295 @@ -21578,6 +21820,8 @@ Double precision `2.225074e-308' `1.797693e+308' floating point (approximate) +Table 15.1: Value Ranges for Different Numeric Representations + ---------- Footnotes ---------- (1) We don't know why they expect this, but they do. @@ -21610,7 +21854,7 @@ material here. number and infinity produce infinity. "NaN" - "Not A Number."(1). A special value that results from attempting a + "Not A Number."(1) A special value that results from attempting a calculation that has no answer as a real number. In such a case, programs can either receive a floating-point exception, or get `NaN' back as the result. The IEEE 754 standard recommends that @@ -21668,37 +21912,38 @@ ranges. (`awk' uses only the 64-bit double precision format.) *note table-ieee-formats:: lists the precision and exponent field values for the basic IEEE 754 binary formats: -Name Total bits Precision emin emax +Name Total bits Precision Minimum Maximum + exponent exponent --------------------------------------------------------------------------- Single 32 24 -126 +127 Double 64 53 -1022 +1023 Quadruple 128 113 -16382 +16383 -Table 15.1: Basic IEEE Format Context Values +Table 15.2: Basic IEEE Format Values NOTE: The precision numbers include the implied leading one that gives them one extra bit of significand. ---------- Footnotes ---------- - (1) Thanks to Michael Brennan for this description, which I have -paraphrased, and for the examples + (1) Thanks to Michael Brennan for this description, which we have +paraphrased, and for the examples. File: gawk.info, Node: MPFR features, Next: FP Math Caution, Prev: Math Definitions, Up: Arbitrary Precision Arithmetic -15.3 Arbitrary Precison Arithmetic Features In `gawk' -===================================================== +15.3 Arbitrary Precision Arithmetic Features In `gawk' +====================================================== -By default, `gawk' uses the double precision floating point values +By default, `gawk' uses the double precision floating-point values supplied by the hardware of the system it runs on. However, if it was -compiled to do, `gawk' uses the GNU MPFR (http://www.mpfr.org) and GNU -MP (http://gmplib.org) (GMP) libraries for arbitrary precision +compiled to do so, `gawk' uses the `http://www.mpfr.org GNU MPFR' and +GNU MP (http://gmplib.org) (GMP) libraries for arbitrary precision arithmetic on numbers. You can see if MPFR support is available like so: $ gawk --version - -| GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) + -| GNU Awk 4.1.2, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) -| Copyright (C) 1989, 1991-2014 Free Software Foundation. ... @@ -21716,10 +21961,11 @@ platform-independent results. With the `-M' command-line option, all floating-point arithmetic operators and numeric functions can yield results to any desired precision level supported by MPFR. - Two built-in variables, `PREC' and `ROUNDMODE', provide control over -the working precision and the rounding mode. The precision and the -rounding mode are set globally for every operation to follow. *Note -Auto-set::, for more information. + Two predefined variables, `PREC' and `ROUNDMODE', provide control +over the working precision and the rounding mode. The precision and +the rounding mode are set globally for every operation to follow. +*Note Setting precision::, and *note Setting the rounding mode::, for +more information. File: gawk.info, Node: FP Math Caution, Next: Arbitrary Precision Integers, Prev: MPFR features, Up: Arbitrary Precision Arithmetic @@ -21833,6 +22079,9 @@ you. Code to do this looks something like this: else # not ok +(We assume that you have a simple absolute value function named `abs()' +defined elsewhere in your program.) + File: gawk.info, Node: Errors accumulate, Prev: Comparing FP Values, Up: Inexactness of computations @@ -21915,7 +22164,7 @@ forget that the finite number of bits used to store the value is often just an approximation after proper rounding. The test for equality succeeds if and only if _all_ bits in the two operands are exactly the same. Since this is not necessarily true after floating-point -computations with a particular precision and effective rounding rule, a +computations with a particular precision and effective rounding mode, a straight test for equality may not work. Instead, compare the two numbers to see if they are within the desirable delta of each other. @@ -21978,7 +22227,7 @@ File: gawk.info, Node: Setting precision, Next: Setting the rounding mode, Pr precision or accuracy of individual numbers. Performing an arithmetic operation or calling a built-in function rounds the result to the current working precision. The default working precision is 53 bits, -which you can modify using the built-in variable `PREC'. You can also +which you can modify using the predefined variable `PREC'. You can also set the value to one of the predefined case-insensitive strings shown in *note table-predefined-precision-strings::, to emulate an IEEE 754 binary format. @@ -21991,7 +22240,7 @@ binary format. `"quad"' Basic 128-bit quadruple precision. `"oct"' 256-bit octuple precision. -Table 15.2: Predefined Precision Strings For `PREC' +Table 15.3: Predefined Precision Strings For `PREC' The following example illustrates the effects of changing precision on arithmetic operations: @@ -22005,7 +22254,7 @@ on arithmetic operations: floating-point constant from program source code, `gawk' uses the default precision (that of a C `double'), unless overridden by an assignment to the special variable `PREC' on the command line, to - store it internally as a MPFR number. Changing the precision + store it internally as an MPFR number. Changing the precision using `PREC' in the program text does _not_ change the precision of a constant. @@ -22044,10 +22293,10 @@ Round toward zero `roundTowardZero' `"Z"' or `"z"' Round to nearest, ties away `roundTiesToAway' `"A"' or `"a"' from zero -Table 15.3: `gawk' Rounding Modes +Table 15.4: `gawk' Rounding Modes `ROUNDMODE' has the default value `"N"', which selects the IEEE 754 -rounding mode `roundTiesToEven'. In *note Table 15.3: +rounding mode `roundTiesToEven'. In *note Table 15.4: table-gawk-rounding-modes, the value `"A"' selects `roundTiesToAway'. This is only available if your version of the MPFR library supports it; otherwise setting `ROUNDMODE' to `"A"' has no effect. @@ -22126,15 +22375,15 @@ using GMP arbitrary precision integers. Any number that looks like an integer in a source or data file is stored as an arbitrary precision integer. The size of the integer is limited only by the available memory. For example, the following computes 5^4^3^2, the result of -which is beyond the limits of ordinary hardware double-precision +which is beyond the limits of ordinary hardware double precision floating point values: $ gawk -M 'BEGIN { > x = 5^4^3^2 - > print "# of digits =", length(x) + > print "number of digits =", length(x) > print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20) > }' - -| # of digits = 183231 + -| number of digits = 183231 -| 62060698786608744707 ... 92256259918212890625 If instead you were to compute the same value using arbitrary @@ -22196,7 +22445,7 @@ user-defined function: # div --- do integer division - function div(numerator, denominator, result, i) + function div(numerator, denominator, result) { split("", result) @@ -22208,6 +22457,39 @@ user-defined function: return 0.0 } + The following example program, contributed by Katie Wasserman, uses +`div()' to compute the digits of pi to as many places as you choose to +set: + + # pi.awk --- compute the digits of pi + + BEGIN { + digits = 100000 + two = 2 * 10 ^ digits + pi = two + for (m = digits * 4; m > 0; --m) { + d = m * 2 + 1 + x = pi * m + div(x, d, result) + pi = result["quotient"] + pi = pi + two + } + print pi + } + + When asked about the algorithm used, Katie replied: + + It's not that well known but it's not that obscure either. It's + Euler's modification to Newton's method for calculating pi. Take + a look at lines (23) - (25) here: + `http://mathworld.wolfram.com/PiFormulas.htm'. + + The algorithm I wrote simply expands the multiply by 2 and works + from the innermost expression outwards. I used this to program HP + calculators because it's quite easy to modify for tiny memory + devices with smallish word sizes. See + `http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899'. + ---------- Footnotes ---------- (1) Weisstein, Eric W. `Sylvester's Sequence'. From MathWorld--A @@ -22309,8 +22591,8 @@ File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Prob ============ * Most computer arithmetic is done using either integers or - floating-point values. The default for `awk' is to use - double-precision floating-point values. + floating-point values. Standard `awk' uses double precision + floating-point values. * In the early 1990's, Barbie mistakenly said "Math class is tough!" While math isn't tough, floating-point arithmetic isn't the same @@ -22411,7 +22693,7 @@ write in C or C++, you can write an extension to do it! Extensions are written in C or C++, using the "Application Programming Interface" (API) defined for this purpose by the `gawk' developers. The rest of this major node explains the facilities that -the API provides and how to use them, and presents a small sample +the API provides and how to use them, and presents a small example extension. In addition, it documents the sample extensions included in the `gawk' distribution, and describes the `gawkextlib' project. *Note Extension Design::, for a discussion of the extension mechanism goals @@ -22423,10 +22705,13 @@ File: gawk.info, Node: Plugin License, Next: Extension Mechanism Outline, Pre 16.2 Extension Licensing ======================== -Every dynamic extension should define the global symbol -`plugin_is_GPL_compatible' to assert that it has been licensed under a -GPL-compatible license. If this symbol does not exist, `gawk' emits a -fatal error and exits when it tries to load your extension. +Every dynamic extension must be distributed under a license that is +compatible with the GNU GPL (*note Copying::). + + In order for the extension to tell `gawk' that it is properly +licensed, the extension must define the global symbol +`plugin_is_GPL_compatible'. If this symbol does not exist, `gawk' +emits a fatal error and exits when it tries to load your extension. The declared type of the symbol should be `int'. It does not need to be in any allocated section, though. The code merely asserts that @@ -22441,7 +22726,7 @@ File: gawk.info, Node: Extension Mechanism Outline, Next: Extension API Descri ================================= Communication between `gawk' and an extension is two-way. First, when -an extension is loaded, it is passed a pointer to a `struct' whose +an extension is loaded, `gawk' passes it a pointer to a `struct' whose fields are function pointers. This is shown in *note figure-load-extension::. @@ -22474,8 +22759,8 @@ Figure 16.1: Loading The Extension The extension can call functions inside `gawk' through these function pointers, at runtime, without needing (link-time) access to `gawk''s symbols. One of these function pointers is to a function for -"registering" new built-in functions. This is shown in *note -figure-load-new-function::. +"registering" new functions. This is shown in *note +figure-register-new-function::. register_ext_func({ "chdir", do_chdir, 1 }); @@ -22489,7 +22774,7 @@ figure-load-new-function::. +-------+-+---+-+---+-+------------------+--------------+-+---+ gawk Main Program Address Space Extension -Figure 16.2: Loading The New Function +Figure 16.2: Registering A New Function In the other direction, the extension registers its new functions with `gawk' by passing function pointers to the functions that provide @@ -22522,8 +22807,8 @@ and understandable. Although all of this sounds somewhat complicated, the result is that extension code is quite straightforward to write and to read. You can -see this in the sample extensions `filefuncs.c' (*note Extension -Example::) and also the `testext.c' code for testing the APIs. +see this in the sample extension `filefuncs.c' (*note Extension +Example::) and also in the `testext.c' code for testing the APIs. Some other bits and pieces: @@ -22554,13 +22839,13 @@ describes the API in detail. * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with `gawk'. * Printing Messages:: Functions for printing messages. * Updating `ERRNO':: Functions for updating `ERRNO'. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -22580,6 +22865,8 @@ through function pointers passed into your extension. API function pointers are provided for the following kinds of operations: + * Allocating, reallocating, and releasing memory. + * Registration functions. You may register: - extension functions, @@ -22604,8 +22891,6 @@ operations: * Symbol table access: retrieving a global variable, creating one, or changing one. - * Allocating, reallocating, and releasing memory. - * Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -22659,9 +22944,8 @@ operations: * All pointers filled in by `gawk' point to memory managed by `gawk' and should be treated by the extension as read-only. Memory for _all_ strings passed into `gawk' from the extension _must_ come - from calling the API-provided function pointers `api_malloc()', - `api_calloc()' or `api_realloc()', and is managed by `gawk' from - then on. + from calling one of `gawk_malloc()', `gawk_calloc()' or + `gawk_realloc()', and is managed by `gawk' from then on. * The API defines several simple `struct's that map values as seen from `awk'. A value can be a `double', a string, or an array (as @@ -22677,7 +22961,7 @@ operations: * When retrieving a value (such as a parameter or that of a global variable or array element), the extension requests a specific type - (number, string, scalars, value cookie, array, or "undefined"). + (number, string, scalar, value cookie, array, or "undefined"). When the request is "undefined," the returned value will have the real underlying type. @@ -22694,7 +22978,7 @@ macros that you should use in your code. This minor node presents the macros as if they were functions. -File: gawk.info, Node: General Data Types, Next: Requesting Values, Prev: Extension API Functions Introduction, Up: Extension API Description +File: gawk.info, Node: General Data Types, Next: Memory Allocation Functions, Prev: Extension API Functions Introduction, Up: Extension API Description 16.4.2 General Purpose Data Types --------------------------------- @@ -22733,9 +23017,8 @@ that use them. `} awk_string_t;' This represents a mutable string. `gawk' owns the memory pointed to if it supplied the value. Otherwise, it takes ownership of the - memory pointed to. *Such memory must come from calling the - API-provided function pointers `api_malloc()', `api_calloc()', or - `api_realloc()'!* + memory pointed to. *Such memory must come from calling one of the + `gawk_malloc()', `gawk_calloc()', or `gawk_realloc()' functions!* As mentioned earlier, strings are maintained using the current multibyte encoding. @@ -22821,7 +23104,7 @@ can obtain a "scalar cookie"(1) object for that variable, and then use the cookie for getting the variable's value or for changing the variable's value. This is the `awk_scalar_t' type and `scalar_cookie' macro. Given a scalar cookie, `gawk' can directly retrieve or modify -the value, as required, without having to first find it. +the value, as required, without having to find it first. The `awk_value_cookie_t' type and `value_cookie' macro are similar. If you know that you wish to use the same numeric or string _value_ for @@ -22840,62 +23123,30 @@ the value. See also the entry for "Cookie" in the *note Glossary::. -File: gawk.info, Node: Requesting Values, Next: Memory Allocation Functions, Prev: General Data Types, Up: Extension API Description - -16.4.3 Requesting Values ------------------------- +File: gawk.info, Node: Memory Allocation Functions, Next: Constructor Functions, Prev: General Data Types, Up: Extension API Description -All of the functions that return values from `gawk' work in the same -way. You pass in an `awk_valtype_t' value to indicate what kind of -value you expect. If the actual value matches what you requested, the -function returns true and fills in the `awk_value_t' result. -Otherwise, the function returns false, and the `val_type' member -indicates the type of the actual value. You may then print an error -message, or reissue the request for the actual value type, as -appropriate. This behavior is summarized in *note -table-value-types-returned::. - - Type of Actual Value: --------------------------------------------------------------------------- - - String Number Array Undefined ------------------------------------------------------------------------------- - String String String false false - Number Number if can Number false false - 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 - -Table 16.1: API Value Types Returned - - -File: gawk.info, Node: Memory Allocation Functions, Next: Constructor Functions, Prev: Requesting Values, Up: Extension API Description - -16.4.4 Memory Allocation Functions and Convenience Macros +16.4.3 Memory Allocation Functions and Convenience Macros --------------------------------------------------------- The API provides a number of "memory allocation" functions for allocating memory that can be passed to `gawk', as well as a number of -convenience macros. +convenience macros. This node presents them all as function +prototypes, in the way that extension code would use them. `void *gawk_malloc(size_t size);' - Call `gawk'-provided `api_malloc()' to allocate storage that may + Call the correct version of `malloc()' to allocate storage that may be passed to `gawk'. `void *gawk_calloc(size_t nmemb, size_t size);' - Call `gawk'-provided `api_calloc()' to allocate storage that may + Call the correct version of `calloc()' to allocate storage that may be passed to `gawk'. `void *gawk_realloc(void *ptr, size_t size);' - Call `gawk'-provided `api_realloc()' to allocate storage that may - be passed to `gawk'. + Call the correct version of `realloc()' to allocate storage that + may be passed to `gawk'. `void gawk_free(void *ptr);' - Call `gawk'-provided `api_free()' to release storage that was + Call the correct version of `free()' to release storage that was allocated with `gawk_malloc()', `gawk_calloc()' or `gawk_realloc()'. @@ -22905,11 +23156,10 @@ C library than was used for the `gawk' executable.(1) If `gawk' were to use its version of `free()' when the memory came from an unrelated version of `malloc()', unexpected behavior would likely result. - Two convenience macros may be used for allocating storage from the -API-provided function pointers `api_malloc()' and `api_realloc()'. If -the allocation fails, they cause `gawk' to exit with a fatal error -message. They should be used as if they were procedure calls that do -not return a value. + Two convenience macros may be used for allocating storage from +`gawk_malloc()' and `gawk_realloc()'. If the allocation fails, they +cause `gawk' to exit with a fatal error message. They should be used +as if they were procedure calls that do not return a value. `#define emalloc(pointer, type, size, message) ...' The arguments to this macro are as follows: @@ -22919,7 +23169,7 @@ not return a value. `type' The type of the pointer variable, used to create a cast for - the call to `api_malloc()'. + the call to `gawk_malloc()'. `size' The total number of bytes to be allocated. @@ -22939,9 +23189,9 @@ not return a value. make_malloced_string(message, strlen(message), & result); `#define erealloc(pointer, type, size, message) ...' - This is like `emalloc()', but it calls `api_realloc()', instead of - `api_malloc()'. The arguments are the same as for the `emalloc()' - macro. + This is like `emalloc()', but it calls `gawk_realloc()', instead + of `gawk_malloc()'. The arguments are the same as for the + `emalloc()' macro. ---------- Footnotes ---------- @@ -22951,7 +23201,7 @@ Unix-like systems as well. File: gawk.info, Node: Constructor Functions, Next: Registration Functions, Prev: Memory Allocation Functions, Up: Extension API Description -16.4.5 Constructor Functions +16.4.4 Constructor Functions ---------------------------- The API provides a number of "constructor" functions for creating @@ -22970,10 +23220,10 @@ extension code would use them. `make_malloced_string(const char *string, size_t length, awk_value_t *result)' This function creates a string value in the `awk_value_t' variable pointed to by `result'. It expects `string' to be a `char *' value - pointing to data previously obtained from the api-provided - functions `api_malloc()', `api_calloc()' or `api_realloc()'. The - idea here is that the data is passed directly to `gawk', which - assumes responsibility for it. It returns `result'. + pointing to data previously obtained from `gawk_malloc()', + `gawk_calloc()' or `gawk_realloc()'. The idea here is that the + data is passed directly to `gawk', which assumes responsibility + for it. It returns `result'. `static inline awk_value_t *' `make_null_string(awk_value_t *result)' @@ -22989,7 +23239,7 @@ extension code would use them. File: gawk.info, Node: Registration Functions, Next: Printing Messages, Prev: Constructor Functions, Up: Extension API Description -16.4.6 Registration Functions +16.4.5 Registration Functions ----------------------------- This minor node describes the API functions for registering parts of @@ -23007,7 +23257,7 @@ your extension with `gawk'. File: gawk.info, Node: Extension Functions, Next: Exit Callback Functions, Up: Registration Functions -16.4.6.1 Registering An Extension Function +16.4.5.1 Registering An Extension Function .......................................... Extension functions are described by the following record: @@ -23025,17 +23275,16 @@ Extension functions are described by the following record: by this name. This is a regular C string. Function names must obey the rules for `awk' identifiers. That is, - they must begin with either a letter or an underscore, which may - be followed by any number of letters, digits, and underscores. - Letter case in function names is significant. + they must begin with either an English letter or an underscore, + 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);' - This is a pointer to the C function that provides the desired - functionality. The function must fill in the result with either a + 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. - As mentioned earlier, string memory *must* come from the - api-provided functions `api_malloc()', `api_calloc()' or - `api_realloc()'. + As mentioned earlier, string memory *must* come from one of + `gawk_malloc()', `gawk_calloc()' or `gawk_realloc()'. The `num_actual_args' argument tells the C function how many actual parameters were passed from the calling `awk' code. @@ -23046,7 +23295,7 @@ Extension functions are described by the following record: `size_t num_expected_args;' This is the 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. Following `awk' functions, it + arguments isn't what it expected. As with real `awk' functions, it is likely OK to ignore extra arguments. Once you have a record representing your extension function, you @@ -23061,7 +23310,7 @@ register it with `gawk' using this API function: File: gawk.info, Node: Exit Callback Functions, Next: Extension Version String, Prev: Extension Functions, Up: Registration Functions -16.4.6.2 Registering An Exit Callback Function +16.4.5.2 Registering An Exit Callback Function .............................................. An "exit callback" function is a function that `gawk' calls before it @@ -23091,7 +23340,7 @@ order--that is, in the reverse order in which they are registered with File: gawk.info, Node: Extension Version String, Next: Input Parsers, Prev: Exit Callback Functions, Up: Registration Functions -16.4.6.3 Registering An Extension Version String +16.4.5.3 Registering An Extension Version String ................................................ You can register a version string which indicates the name and version @@ -23107,7 +23356,7 @@ invoked with the `--version' option. File: gawk.info, Node: Input Parsers, Next: Output Wrappers, Prev: Extension Version String, Up: Registration Functions -16.4.6.4 Customized Input Parsers +16.4.5.4 Customized Input Parsers ................................. By default, `gawk' reads text files as its input. It uses the value of @@ -23276,7 +23525,7 @@ records. The parameters are as follows: `*rt_start' should be set to point to the data to be used for `RT', and `*rt_len' should be set to the length of the data. Otherwise, `*rt_len' should be set to zero. `gawk' makes its own - copy of this data, so the extension must manage the storage. + copy of this data, so the extension must manage this storage. The return value is the length of the buffer pointed to by `*out', or `EOF' if end-of-file was reached or an error occurred. @@ -23330,7 +23579,7 @@ whether or not to activate an input parser (*note BEGINFILE/ENDFILE::). File: gawk.info, Node: Output Wrappers, Next: Two-way processors, Prev: Input Parsers, Up: Registration Functions -16.4.6.5 Customized Output Wrappers +16.4.5.5 Customized Output Wrappers ................................... An "output wrapper" is the mirror image of an input parser. It allows @@ -23437,7 +23686,7 @@ just use normally. File: gawk.info, Node: Two-way processors, Prev: Output Wrappers, Up: Registration Functions -16.4.6.6 Customized Two-way Processors +16.4.5.6 Customized Two-way Processors ...................................... A "two-way processor" combines an input parser and an output wrapper for @@ -23490,7 +23739,7 @@ can take this" and "take over for this" functions, File: gawk.info, Node: Printing Messages, Next: Updating `ERRNO', Prev: Registration Functions, Up: Extension API Description -16.4.7 Printing Messages +16.4.6 Printing Messages ------------------------ You can print different kinds of warning messages from your extension, @@ -23519,9 +23768,9 @@ of the ISO C 99 variadic macro feature to hide that parameter. More's the pity. -File: gawk.info, Node: Updating `ERRNO', Next: Accessing Parameters, Prev: Printing Messages, Up: Extension API Description +File: gawk.info, Node: Updating `ERRNO', Next: Requesting Values, Prev: Printing Messages, Up: Extension API Description -16.4.8 Updating `ERRNO' +16.4.7 Updating `ERRNO' ----------------------- The following functions allow you to update the `ERRNO' variable: @@ -23536,11 +23785,44 @@ The following functions allow you to update the `ERRNO' variable: Set `ERRNO' directly to the string value of `ERRNO'. `gawk' makes a copy of the value of `string'. -`void unset_ERRNO();' +`void unset_ERRNO(void);' Unset `ERRNO'. -File: gawk.info, Node: Accessing Parameters, Next: Symbol Table Access, Prev: Updating `ERRNO', Up: Extension API Description +File: gawk.info, Node: Requesting Values, Next: Accessing Parameters, Prev: Updating `ERRNO', Up: Extension API Description + +16.4.8 Requesting Values +------------------------ + +All of the functions that return values from `gawk' work in the same +way. You pass in an `awk_valtype_t' value to indicate what kind of +value you expect. If the actual value matches what you requested, the +function returns true and fills in the `awk_value_t' result. +Otherwise, the function returns false, and the `val_type' member +indicates the type of the actual value. You may then print an error +message, or reissue the request for the actual value type, as +appropriate. This behavior is summarized in *note +table-value-types-returned::. + + Type of Actual Value: +-------------------------------------------------------------------------- + + String Number Array Undefined +------------------------------------------------------------------------------ + String String String false false + Number Number if can Number false false + 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 + +Table 16.1: API Value Types Returned + + +File: gawk.info, Node: Accessing Parameters, Next: Symbol Table Access, Prev: Requesting Values, Up: Extension API Description 16.4.9 Accessing and Updating Parameters ---------------------------------------- @@ -23598,7 +23880,7 @@ termed a "symbol table". Fill in the `awk_value_t' structure pointed to by `result' with the value of the variable named by the string `name', which is a regular C string. `wanted' indicates the type of value expected. - Return true if the actual type matches `wanted', false otherwise + Return true if the actual type matches `wanted', false otherwise. In the latter case, `result->val_type' indicates the actual type (*note Table 16.1: table-value-types-returned.). @@ -23616,7 +23898,7 @@ termed a "symbol table". However, with the exception of the `PROCINFO' array, an extension cannot change any of those variables. - NOTE: It is possible for the lookup of `PROCINFO' to fail. This + 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. @@ -23638,14 +23920,14 @@ was discussed earlier, in *note General Data Types::. ` awk_valtype_t wanted,' ` awk_value_t *result);' Retrieve the current value of a scalar cookie. Once you have - obtained a scalar_cookie using `sym_lookup()', you can use this + obtained a scalar cookie using `sym_lookup()', you can use this function to get its value more efficiently. Return false if the value cannot be retrieved. `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 built-in variables may not be updated. + 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 @@ -23697,7 +23979,7 @@ usual. Then get a scalar cookie for the variable using `sym_lookup()': /* install initial value */ sym_update("MAGIC_VAR", make_number(42.0, & value)); - /* get cookie */ + /* get the cookie */ sym_lookup("MAGIC_VAR", AWK_SCALAR, & value); /* save the cookie */ @@ -23748,7 +24030,7 @@ variables using `sym_update()' or `sym_update_scalar()', as you like. However, you can understand the point of cached values if you remember that _every_ string value's storage _must_ come from -`api_malloc()', `api_calloc()' or `api_realloc()'. If you have 20 +`gawk_malloc()', `gawk_calloc()' or `gawk_realloc()'. If you have 20 variables, all of which have the same string value, you must create 20 identical copies of the string.(1) @@ -23812,8 +24094,8 @@ Using value cookies in this way saves considerable storage, since all of `VAR1' through `VAR100' share the same value. You might be wondering, "Is this sharing problematic? What happens -if `awk' code assigns a new value to `VAR1', are all the others be -changed too?" +if `awk' code assigns a new value to `VAR1', are all the others changed +too?" That's a great question. The answer is that no, it's not a problem. Internally, `gawk' uses "reference-counted strings". This means that @@ -23879,7 +24161,7 @@ The data types associated with arrays are listed below. ` struct awk_element *next;' ` enum {' ` AWK_ELEMENT_DEFAULT = 0, /* set by gawk */' -` AWK_ELEMENT_DELETE = 1 /* set by extension if should be deleted */' +` AWK_ELEMENT_DELETE = 1 /* set by extension */' ` } flags;' ` awk_value_t index;' ` awk_value_t value;' @@ -23897,8 +24179,8 @@ The data types associated with arrays are listed below. the list. `enum { ... } flags;' - A set of flag values that convey information between `gawk' - and the extension. Currently there is only one: + A set of flag values that convey information between the + extension and `gawk'. Currently there is only one: `AWK_ELEMENT_DELETE'. Setting it causes `gawk' to delete the element from the original array upon release of the flattened array. @@ -23909,8 +24191,8 @@ The data types associated with arrays are listed below. memory pointed to by `index' and `value' belongs to `gawk'. `typedef struct awk_flat_array {' -` awk_const void *awk_const opaque1; /* private data for use by gawk */' -` awk_const void *awk_const opaque2; /* private data for use by gawk */' +` awk_const void *awk_const opaque1; /* for use by gawk */' +` awk_const void *awk_const opaque2; /* for use by gawk */' ` awk_const size_t count; /* how many elements */' ` awk_element_t elements[1]; /* will be extended */' `} awk_flat_array_t;' @@ -23934,7 +24216,7 @@ File: gawk.info, Node: Array Functions, Next: Flattening Arrays, Prev: Array The following functions relate to individual array elements. `awk_bool_t get_element_count(awk_array_t a_cookie, size_t *count);' - For the array represented by `a_cookie', return in `*count' the + For the array represented by `a_cookie', place in `*count' the number of elements it contains. A subarray counts as a single element. Return false if there is an error. @@ -23954,9 +24236,9 @@ The following functions relate to individual array elements. strings (*note Conversion::); thus using integral values is safest. As with _all_ strings passed into `gawk' from an extension, the - string value of `index' must come from the API-provided functions - `api_malloc()', `api_calloc()' or `api_realloc()' and `gawk' - releases the storage. + string value of `index' must come from `gawk_malloc()', + `gawk_calloc()' or `gawk_realloc()', and `gawk' releases the + storage. `awk_bool_t set_array_element(awk_array_t a_cookie,' ` const awk_value_t *const index,' @@ -23978,7 +24260,7 @@ The following functions relate to individual array elements. The following functions relate to arrays as a whole: -`awk_array_t create_array();' +`awk_array_t create_array(void);' Create a new array to which elements may be added. *Note Creating Arrays::, for a discussion of how to create a new array and add elements to it. @@ -24014,7 +24296,8 @@ array in a fashion that makes it easy for C code to traverse the entire array. Test code in `extension/testext.c' does this, and also serves as a nice example showing how to use the APIs. - First, the `gawk' script that drives the test extension: + We walk through that part of the code one step at a time. First, +the `gawk' script that drives the test extension: @load "testext" BEGIN { @@ -24135,8 +24418,7 @@ flag bit set: valrep2str(& flat_array->elements[i].value)); if (strcmp(value3.str_value.str, - flat_array->elements[i].index.str_value.str) - == 0) { + flat_array->elements[i].index.str_value.str) == 0) { flat_array->elements[i].flags |= AWK_ELEMENT_DELETE; printf("dump_array_and_delete: marking element \"%s\" " "for deletion\n", @@ -24226,9 +24508,9 @@ code: The following C code is a simple test extension to create an array with two regular elements and with a subarray. The leading `#include' -directives and boilerplate variable declarations are omitted for -brevity. The first step is to create a new array and then install it -in the symbol table: +directives and boilerplate variable declarations (*note Extension API +Boilerplate::) are omitted for brevity. The first step is to create a +new array and then install it in the symbol table: /* create_new_array --- create a named array */ @@ -24415,8 +24697,8 @@ invoked. The variables are: option. The value of `do_lint' can change if `awk' code modifies the `LINT' -built-in variable (*note Built-in Variables::). The others should not -change during execution. +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 @@ -24450,12 +24732,12 @@ in the `gawkapi.h' header file: /* OR: */ static awk_bool_t - init_my_module(void) + init_my_extension(void) { ... } - static awk_bool_t (*init_func)(void) = init_my_module; + static awk_bool_t (*init_func)(void) = init_my_extension; dl_load_func(func_table, some_name, "name_space_in_quotes") @@ -24487,8 +24769,8 @@ in the `gawkapi.h' header file: `static awk_bool_t (*init_func)(void) = NULL;' ` OR' -`static awk_bool_t init_my_module(void) { ... }' -`static awk_bool_t (*init_func)(void) = init_my_module;' +`static awk_bool_t init_my_extension(void) { ... }' +`static awk_bool_t (*init_func)(void) = init_my_extension;' If you need to do some initialization work, you should define a function that does it (creates variables, opens files, etc.) and then define the `init_func' pointer to point to your function. @@ -24542,8 +24824,9 @@ File: gawk.info, Node: Extension Example, Next: Extension Samples, Prev: Find Two useful functions that are not in `awk' are `chdir()' (so that an `awk' program can change its directory) and `stat()' (so that an `awk' -program can gather information about a file). This minor node -implements these functions for `gawk' in an extension. +program can gather information about a file). In order to illustrate +the API in action, this minor node implements these functions for +`gawk' in an extension. * Menu: @@ -24567,8 +24850,7 @@ directory to change to: newdir = "/home/arnold/funstuff" ret = chdir(newdir) if (ret < 0) { - printf("could not change to %s: %s\n", - newdir, ERRNO) > "/dev/stderr" + printf("could not change to %s: %s\n", newdir, ERRNO) > "/dev/stderr" exit 1 } ... @@ -24733,7 +25015,7 @@ arguments: the first is an `int' usually called `nargs', that represents the number of actual arguments for the function. The second is a pointer to an `awk_value_t', usually named `result'. - /* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ + /* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * do_chdir(int nargs, awk_value_t *result) @@ -24921,12 +25203,20 @@ and/or the type of the file. It then returns zero, for success: } } - array_set(array, "type", make_const_string(type, strlen(type), &tmp)); + array_set(array, "type", make_const_string(type, strlen(type), & tmp)); return 0; } - Finally, here is the `do_stat()' function. It starts with variable + The third argument to `stat()' was not discussed previously. This +argument is optional. If present, it causes `do_stat()' to use the +`stat()' system call instead of the `lstat()' system call. This is +done by using a function pointer: `statfunc'. `statfunc' is +initialized to point to `lstat()' (instead of `stat()') to get the file +information, in case the file is a symbolic link. However, if there +were three arguments, `statfunc' is set point to `stat()', instead. + + Here is the `do_stat()' function. It starts with variable declarations and argument checking: /* do_stat --- provide a stat() function for gawk */ @@ -24951,14 +25241,10 @@ declarations and argument checking: return make_number(-1, result); } - The third argument to `stat()' was not discussed previously. This -argument is optional. If present, it causes `stat()' to use the `stat()' -system call instead of the `lstat()' system call. - Then comes the actual work. First, the function gets the arguments. -Next, it gets the information for the file. The code use `lstat()' -(instead of `stat()') to get the file information, in case the file is -a symbolic link. If there's an error, it sets `ERRNO' and returns: +Next, it gets the information for the file. If the called function +(`lstat()' or `stat()') returns an error, the code sets `ERRNO' and +returns: /* file is first arg, array to hold results is second */ if ( ! get_argument(0, AWK_STRING, & file_param) @@ -24985,7 +25271,7 @@ a symbolic link. If there's an error, it sets `ERRNO' and returns: } The tedious work is done by `fill_stat_array()', shown earlier. -When done, return the result from `fill_stat_array()': +When done, the function returns the result from `fill_stat_array()': ret = fill_stat_array(name, array, & sbuf); @@ -25067,14 +25353,14 @@ create a GNU/Linux shared library: for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] print "testff.awk modified:", - strftime("%m %d %y %H:%M:%S", data["mtime"]) + strftime("%m %d %Y %H:%M:%S", data["mtime"]) print "\nInfo for JUNK" ret = stat("JUNK", data) print "ret =", ret for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] - print "JUNK modified:", strftime("%m %d %y %H:%M:%S", data["mtime"]) + print "JUNK modified:", strftime("%m %d %Y %H:%M:%S", data["mtime"]) } The `AWKLIBPATH' environment variable tells `gawk' where to find @@ -25086,32 +25372,33 @@ directory and run the program: -| Info for testff.awk -| ret = 0 -| data["blksize"] = 4096 - -| data["mtime"] = 1350838628 + -| data["devbsize"] = 512 + -| data["mtime"] = 1412004710 -| data["mode"] = 33204 -| data["type"] = file -| data["dev"] = 2053 -| data["gid"] = 1000 - -| data["ino"] = 1719496 - -| data["ctime"] = 1350838628 + -| data["ino"] = 10358899 + -| data["ctime"] = 1412004710 -| data["blocks"] = 8 -| data["nlink"] = 1 -| data["name"] = testff.awk - -| data["atime"] = 1350838632 + -| data["atime"] = 1412004716 -| data["pmode"] = -rw-rw-r-- - -| data["size"] = 662 + -| data["size"] = 666 -| data["uid"] = 1000 - -| testff.awk modified: 10 21 12 18:57:08 + -| testff.awk modified: 09 29 2014 18:31:50 -| -| Info for JUNK -| ret = -1 - -| JUNK modified: 01 01 70 02:00:00 + -| JUNK modified: 01 01 1970 02:00:00 ---------- Footnotes ---------- (1) In practice, you would probably want to use the GNU Autotools--Automake, Autoconf, Libtool, and `gettext'--to configure and build your libraries. Instructions for doing so are beyond the scope of -this Info file. *Note gawkextlib::, for WWW links to the tools. +this Info file. *Note gawkextlib::, for Internet links to the tools. File: gawk.info, Node: Extension Samples, Next: gawkextlib, Prev: Extension Example, Up: Dynamic Extensions @@ -25139,9 +25426,9 @@ the extension API. * Extension Sample Rev2way:: Reversing data sample two-way processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to `gettimeofday()' and `sleep()'. +* Extension Sample API Tests:: Tests for the API. File: gawk.info, Node: Extension Sample File Functions, Next: Extension Sample Fnmatch, Up: Extension Samples @@ -25152,7 +25439,7 @@ File: gawk.info, Node: Extension Sample File Functions, Next: Extension Sample The `filefuncs' extension provides three different functions, as follows: The usage is: -@load "filefuncs" +`@load "filefuncs"' This is how you load the extension. `result = chdir("/some/directory")' @@ -25208,8 +25495,8 @@ follows: The usage is: `result = fts(pathlist, flags, filedata)' Walk the file trees provided in `pathlist' and fill in the `filedata' array as described below. `flags' is the bitwise OR of - several predefined constant values, also described below. Return - zero if there were no errors, otherwise return -1. + several predefined values, also described below. Return zero if + there were no errors, otherwise return -1. The `fts()' function provides a hook to the C library `fts()' routines for traversing file hierarchies. Instead of returning data @@ -25250,10 +25537,10 @@ requested hierarchies. whether or not `FTS_LOGICAL' is set. `FTS_SEEDOT' - By default, the `fts()' routines do not return entries for - `.' (dot) and `..' (dot-dot). This option causes entries for - dot-dot to also be included. (The extension always includes - an entry for dot, see below.) + By default, the C library `fts()' routines do not return + entries for `.' (dot) and `..' (dot-dot). This option causes + entries for dot-dot to also be included. (The extension + always includes an entry for dot, see below.) `FTS_XDEV' During a traversal, do not cross onto a different mounted @@ -25303,15 +25590,16 @@ Otherwise it returns -1. NOTE: The `fts()' extension does not exactly mimic the interface of the C library `fts()' routines, choosing instead to provide an - interface that is based on associative arrays, which should be - more comfortable to use from an `awk' program. This includes the - lack of a comparison function, since `gawk' already provides - powerful array sorting facilities. While an `fts_read()'-like - interface could have been provided, this felt less natural than - simply creating a multidimensional array to represent the file - hierarchy and its information. + interface that is based on associative arrays, which is more + comfortable to use from an `awk' program. This includes the lack + of a comparison function, since `gawk' already provides powerful + array sorting facilities. While an `fts_read()'-like interface + could have been provided, this felt less natural than simply + creating a multidimensional array to represent the file hierarchy + and its information. - See `test/fts.awk' in the `gawk' distribution for an example. + See `test/fts.awk' in the `gawk' distribution for an example use of +the `fts()' extension function. File: gawk.info, Node: Extension Sample Fnmatch, Next: Extension Sample Fork, Prev: Extension Sample File Functions, Up: Extension Samples @@ -25492,8 +25780,8 @@ returned as a record. number and the file name, separated by a forward slash character. On systems where the directory entry contains the file type, the record has a third field (also separated by a slash) which is a single letter -indicating the type of the file. The letters are file types are shown -in *note table-readdir-file-types::. +indicating the type of the file. The letters and their corresponding +file types are shown in *note table-readdir-file-types::. Letter File Type -------------------------------------------------------------------------- @@ -25506,7 +25794,7 @@ Letter File Type `s' Socket `u' Anything else (unknown) -Table 16.2: File Types Returned By `readdir()' +Table 16.2: File Types Returned By The `readdir' Extension On systems without the file type information, the third field is always `u'. @@ -25577,6 +25865,9 @@ File: gawk.info, Node: Extension Sample Read write array, Next: Extension Samp The `rwarray' extension adds two functions, named `writea()' and `reada()', as follows: +`@load "rwarray"' + This is how you load the extension. + `ret = writea(file, array)' This function takes a string argument, which is the name of the file to which to dump the array, and the array itself as the @@ -25613,7 +25904,7 @@ restored on systems with a different one, but this has not been tried. ret = reada("arraydump.bin", array) -File: gawk.info, Node: Extension Sample Readfile, Next: Extension Sample API Tests, Prev: Extension Sample Read write array, Up: Extension Samples +File: gawk.info, Node: Extension Sample Readfile, Next: Extension Sample Time, Prev: Extension Sample Read write array, Up: Extension Samples 16.7.10 Reading An Entire File ------------------------------ @@ -25646,21 +25937,9 @@ an input parser: } -File: gawk.info, Node: Extension Sample API Tests, Next: Extension Sample Time, Prev: Extension Sample Readfile, Up: Extension Samples - -16.7.11 API Tests ------------------ - -The `testext' extension exercises parts of the extension API that are -not tested by the other samples. The `extension/testext.c' file -contains both the C code for the extension and `awk' test code inside C -comments that run the tests. The testing framework extracts the `awk' -code and runs the tests. See the source file for more information. - - -File: gawk.info, Node: Extension Sample Time, Prev: Extension Sample API Tests, Up: Extension Samples +File: gawk.info, Node: Extension Sample Time, Next: Extension Sample API Tests, Prev: Extension Sample Readfile, Up: Extension Samples -16.7.12 Extension Time Functions +16.7.11 Extension Time Functions -------------------------------- The `time' extension adds two functions, named `gettimeofday()' and @@ -25689,6 +25968,18 @@ The `time' extension adds two functions, named `gettimeofday()' and delay. +File: gawk.info, Node: Extension Sample API Tests, Prev: Extension Sample Time, Up: Extension Samples + +16.7.12 API Tests +----------------- + +The `testext' extension exercises parts of the extension API that are +not tested by the other samples. The `extension/testext.c' file +contains both the C code for the extension and `awk' test code inside C +comments that run the tests. The testing framework extracts the `awk' +code and runs the tests. See the source file for more information. + + File: gawk.info, Node: gawkextlib, Next: Extension summary, Prev: Extension Samples, Up: Dynamic Extensions 16.8 The `gawkextlib' Project @@ -25701,21 +25992,17 @@ project. As of this writing, there are five extensions: - * XML parser extension, using the Expat - (http://expat.sourceforge.net) XML parsing library. + * GD graphics library extension. * PDF extension. * PostgreSQL extension. - * GD graphics library extension. - * MPFR library extension. This provides access to a number of MPFR functions which `gawk''s native MPFR support does not. - The `time' extension described earlier (*note Extension Sample -Time::) was originally from this project but has been moved in to the -main `gawk' distribution. + * XML parser extension, using the Expat + (http://expat.sourceforge.net) XML parsing library. You can check out the code for the `gawkextlib' project using the Git (http://git-scm.com) distributed source code control system. The @@ -25779,7 +26066,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga tasks. * One of these tasks is to "register" the name and implementation of - a new `awk'-level function with `gawk'. The implementation takes + new `awk'-level functions with `gawk'. The implementation takes the form of a C function pointer with a defined signature. By convention, implementation functions are named `do_XXXX()' for some `awk'-level function `XXXX()'. @@ -25791,6 +26078,8 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga * API function pointers are provided for the following kinds of operations: + * Allocating, reallocating, and releasing memory. + * Registration functions. You may register extension functions, exit callbacks, a version string, input parsers, output wrappers, and two-way processors. @@ -25805,8 +26094,6 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga * Symbol table access: retrieving a global variable, creating one, or changing one. - * Allocating, reallocating, and releasing memory. - * Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -25815,7 +26102,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga modifying elements; getting the count of elements in an array; creating a new array; clearing an array; and flattening an array for easy C style looping over all its indices and - elements + elements. * The API defines a number of standard data types for representing `awk' values, array elements, and arrays. @@ -25830,7 +26117,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga * _All_ memory passed from an extension to `gawk' must come from the API's memory allocation functions. `gawk' takes responsibility for - the memory and will release it when appropriate. + the memory and releases it when appropriate. * The API provides information about the running version of `gawk' so that an extension can make sure it is compatible with the `gawk' @@ -25844,7 +26131,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga sample extensions. The `gawkextlib' project includes several more, larger, extensions. If you wish to write an extension and contribute it to the community of `gawk' users, the `gawkextlib' - project should be the place to do so. + project is the place to do so. @@ -25877,11 +26164,11 @@ This Info file describes the GNU implementation of `awk', which follows the POSIX specification. Many long-time `awk' users learned `awk' programming with the original `awk' implementation in Version 7 Unix. (This implementation was the basis for `awk' in Berkeley Unix, through -4.3-Reno. Subsequent versions of Berkeley Unix, and some systems -derived from 4.4BSD-Lite, used various versions of `gawk' for their -`awk'.) This major node briefly describes the evolution of the `awk' -language, with cross-references to other parts of the Info file where -you can find more information. +4.3-Reno. Subsequent versions of Berkeley Unix, and, for a while, some +systems derived from 4.4BSD-Lite, used various versions of `gawk' for +their `awk'.) This major node briefly describes the evolution of the +`awk' language, with cross-references to other parts of the Info file +where you can find more information. * Menu: @@ -25931,7 +26218,7 @@ the changes, with cross-references to further details: Functions::). * The `ARGC', `ARGV', `FNR', `RLENGTH', `RSTART', and `SUBSEP' - built-in variables (*note Built-in Variables::). + predefined variables (*note Built-in Variables::). * Assignable `$0' (*note Changing Fields::). @@ -25952,12 +26239,10 @@ the changes, with cross-references to further details: Functions::), rather than using only the first character of `FS'. * Dynamic regexps as operands of the `~' and `!~' operators (*note - Regexp Usage::). + Computed Regexps::). * The escape sequences `\b', `\f', and `\r' (*note Escape - Sequences::). (Some vendors have updated their old versions of - `awk' to recognize `\b', `\f', and `\r', but this is not something - you can rely on.) + Sequences::). * Redirection of input for the `getline' function (*note Getline::). @@ -25981,7 +26266,7 @@ The System V Release 4 (1989) version of Unix `awk' added these features * The `-v' option for assigning variables before program execution begins (*note Options::). - * The `--' option for terminating command-line options. + * The `--' signal for terminating command-line options. * The `\a', `\v', and `\x' escape sequences (*note Escape Sequences::). @@ -25996,8 +26281,8 @@ The System V Release 4 (1989) version of Unix `awk' added these features `printf' function (*note Control Letters::). * The ability to dynamically pass the field width and precision - (`"%*.*d"') in the argument list of the `printf' function (*note - Control Letters::). + (`"%*.*d"') in the argument list of `printf' and `sprintf()' + (*note Control Letters::). * The use of regexp constants, such as `/foo/', as expressions, where they are equivalent to using the matching operator, as in `$0 ~ @@ -26024,8 +26309,8 @@ introduced the following changes into the language: * The concept of a numeric string and tighter comparison rules to go with it (*note Typing and Comparison::). - * The use of built-in variables as function parameter names is - forbidden (*note Definition Syntax::. + * The use of predefined variables as function parameter names is + forbidden (*note Definition Syntax::). * More complete documentation of many of the previously undocumented features of the language. @@ -26087,7 +26372,7 @@ can all be disabled with either the `--traditional' or `--posix' options node summarizes the additional features over POSIX `awk' that are in the current version of `gawk'. - * Additional built-in variables: + * Additional predefined variables: - The `ARGIND' `BINMODE', `ERRNO', `FIELDWIDTHS', `FPAT', `IGNORECASE', `LINT', `PROCINFO', `RT', and `TEXTDOMAIN' @@ -26129,11 +26414,6 @@ the current version of `gawk'. - The `BEGINFILE' and `ENDFILE' special patterns. (*note BEGINFILE/ENDFILE::). - - The ability to delete all of an array at once with `delete - ARRAY' (*note Delete::). - - - The `nextfile' statement (*note Nextfile Statement::). - - The `switch' statement (*note Switch Statement::). * Changes to standard `awk' functions: @@ -26142,7 +26422,7 @@ the current version of `gawk'. one end of a two-way pipe to a coprocess (*note Two-way I/O::). - - POSIX compliance for `gsub()' and `sub()'. + - POSIX compliance for `gsub()' and `sub()' with `--posix'. - The `length()' function accepts an array argument and returns the number of elements in the array (*note String @@ -26161,24 +26441,24 @@ the current version of `gawk'. * Additional functions only in `gawk': - - The `and()', `compl()', `lshift()', `or()', `rshift()', and - `xor()' functions for bit manipulation (*note Bitwise - Functions::). + - The `gensub()', `patsplit()', and `strtonum()' functions for + more powerful text manipulation (*note String Functions::). - The `asort()' and `asorti()' functions for sorting arrays (*note Array Sorting::). - - The `bindtextdomain()', `dcgettext()' and `dcngettext()' - functions for internationalization (*note Programmer i18n::). + - The `mktime()', `systime()', and `strftime()' functions for + working with timestamps (*note Time Functions::). - - The `fflush()' function from BWK `awk' (*note I/O + - The `and()', `compl()', `lshift()', `or()', `rshift()', and + `xor()' functions for bit manipulation (*note Bitwise Functions::). - - The `gensub()', `patsplit()', and `strtonum()' functions for - more powerful text manipulation (*note String Functions::). + - The `isarray()' function to check if a variable is an array + or not (*note Type Functions::). - - The `mktime()', `systime()', and `strftime()' functions for - working with timestamps (*note Time Functions::). + - The `bindtextdomain()', `dcgettext()' and `dcngettext()' + functions for internationalization (*note Programmer i18n::). * Changes and/or additions in the command-line options: @@ -26230,7 +26510,7 @@ the current version of `gawk'. * Support for the following obsolete systems was removed from the - code and the documentation for `gawk' version 4.1: + code for `gawk' version 4.1: - Ultrix @@ -26605,7 +26885,7 @@ in POSIX `awk', in the order they were added to `gawk'. - The `-M' and `--bignum' options enable MPFR. - - The `-o' only does pretty-printing. + - The `-o' option only does pretty-printing. - The `-p' option is used for profiling. @@ -26628,30 +26908,26 @@ File: gawk.info, Node: Common Extensions, Next: Ranges and Locales, Prev: Fea A.7 Common Extensions Summary ============================= -This minor node summarizes the common extensions supported by `gawk', -Brian Kernighan's `awk', and `mawk', the three most widely-used freely -available versions of `awk' (*note Other Versions::). - -Feature BWK Awk Mawk GNU Awk --------------------------------------------------------- -`\x' Escape sequence X X X -`FS' as null string X X X -`/dev/stdin' special file X X X -`/dev/stdout' special file X X X -`/dev/stderr' special file X X X -`delete' without subscript X X X -`fflush()' function X X X -`length()' of an array X X X -`nextfile' statement X X X -`**' and `**=' operators X X -`func' keyword X X -`BINMODE' variable X X -`RS' as regexp X X -Time related functions X X - - (Technically speaking, as of late 2012, `fflush()', `delete ARRAY', -and `nextfile' are no longer extensions, since they have been added to -POSIX.) +The following table summarizes the common extensions supported by +`gawk', Brian Kernighan's `awk', and `mawk', the three most widely-used +freely available versions of `awk' (*note Other Versions::). + +Feature BWK Awk Mawk GNU Awk Now standard +----------------------------------------------------------------------- +`\x' Escape sequence X X X +`FS' as null string X X X +`/dev/stdin' special file X X X +`/dev/stdout' special file X X X +`/dev/stderr' special file X X X +`delete' without subscript X X X X +`fflush()' function X X X X +`length()' of an array X X X +`nextfile' statement X X X X +`**' and `**=' operators X X +`func' keyword X X +`BINMODE' variable X X +`RS' as regexp X X +Time related functions X X File: gawk.info, Node: Ranges and Locales, Next: Contributors, Prev: Common Extensions, Up: Language History @@ -26692,14 +26968,14 @@ like `[a-dx-z]' is still equivalent to `[abcdxyz]', as in ASCII. But outside those locales, the ordering was defined to be based on "collation order". - In many locales, `A' and `a' are both less than `B'. In other -words, these locales sort characters in dictionary order, and -`[a-dx-z]' is typically not equivalent to `[abcdxyz]'; instead it might -be equivalent to `[ABCXYabcdxyz]', for example. + What does that mean? In many locales, `A' and `a' are both less +than `B'. In other words, these locales sort characters in dictionary +order, and `[a-dx-z]' is typically not equivalent to `[abcdxyz]'; +instead it might be equivalent to `[ABCXYabcdxyz]', for example. This point needs to be emphasized: Much literature teaches that you should use `[a-z]' to match a lowercase character. But on systems with -non-ASCII locales, this also matched all of the uppercase characters +non-ASCII locales, this also matches all of the uppercase characters except `A' or `Z'! This was a continuous cause of confusion, even well into the twenty-first century. @@ -26826,7 +27102,7 @@ Info file, in approximate chronological order: various PC platforms. * Christos Zoulas provided the `extension()' built-in function for - dynamically adding new modules. (This was obsoleted at `gawk' + dynamically adding new functions. (This was obsoleted at `gawk' 4.1.) * Ju"rgen Kahrs contributed the initial version of the TCP/IP @@ -26896,6 +27172,9 @@ Info file, in approximate chronological order: 4.1 was driven primarily by Arnold Robbins and Andrew Schorr, with notable contributions from the rest of the development team. + * John Malmberg contributed significant improvements to the OpenVMS + port and the related documentation. + * Antonio Giovanni Colombo rewrote a number of examples in the early chapters that were severely dated, for which I am incredibly grateful. @@ -26946,7 +27225,7 @@ This appendix provides instructions for installing `gawk' on the various platforms that are supported by the developers. The primary developer supports GNU/Linux (and Unix), whereas the other ports are contributed. *Note Bugs::, for the electronic mail addresses of the -people who did the respective ports. +people who maintain the respective ports. * Menu: @@ -26989,7 +27268,7 @@ There are two ways to get GNU software: supported. If you have the `wget' program, you can use a command like the following: - wget http://ftp.gnu.org/gnu/gawk/gawk-4.1.1.tar.gz + wget http://ftp.gnu.org/gnu/gawk/gawk-4.1.2.tar.gz The GNU software archive is mirrored around the world. The up-to-date list of mirror sites is available from the main FSF web site @@ -27008,25 +27287,25 @@ compression programs: `gzip', `bzip2', and `xz'. For simplicity, the rest of these instructions assume you are using the one compressed with the GNU Zip program, `gzip'. - Once you have the distribution (for example, `gawk-4.1.1.tar.gz'), + Once you have the distribution (for example, `gawk-4.1.2.tar.gz'), use `gzip' to expand the file and then use `tar' to extract it. You can use the following pipeline to produce the `gawk' distribution: - gzip -d -c gawk-4.1.1.tar.gz | tar -xvpf - + gzip -d -c gawk-4.1.2.tar.gz | tar -xvpf - On a system with GNU `tar', you can let `tar' do the decompression for you: - tar -xvpzf gawk-4.1.1.tar.gz + tar -xvpzf gawk-4.1.2.tar.gz -Extracting the archive creates a directory named `gawk-4.1.1' in the +Extracting the archive creates a directory named `gawk-4.1.2' in the current directory. The distribution file name is of the form `gawk-V.R.P.tar.gz'. The V represents the major version of `gawk', the R represents the current release of version V, and the P represents a "patch level", meaning that minor bugs have been fixed in the release. The current patch -level is 1, but when retrieving distributions, you should get the +level is 2, but when retrieving distributions, you should get the version with the highest version, release, and patch level. (Note, however, that patch levels greater than or equal to 70 denote "beta" or nonproduction software; you might not want to retrieve such a version @@ -27193,6 +27472,13 @@ Various `.c', `.y', and `.h' files sample extensions included with `gawk'. *Note Dynamic Extensions::, for more information. +`extras/*' + Additional non-essential files. Currently, this directory + contains some shell startup files to be installed in + `/etc/profile.d' to aid in manipulating the `AWKPATH' and + `AWKLIBPATH' environment variables. *Note Shell Startup Files::, + for more information. + `posix/*' Files needed for building `gawk' on POSIX-compliant systems. @@ -27223,11 +27509,12 @@ configure `gawk' for your system yourself. * Menu: * Quick Installation:: Compiling `gawk' under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. -File: gawk.info, Node: Quick Installation, Next: Additional Configuration Options, Up: Unix Installation +File: gawk.info, Node: Quick Installation, Next: Shell Startup Files, Up: Unix Installation B.2.1 Compiling `gawk' for Unix-like Systems -------------------------------------------- @@ -27237,12 +27524,12 @@ Unix-derived systems, GNU/Linux, BSD-based systems, and the Cygwin environment for MS-Windows. After you have extracted the `gawk' distribution, `cd' to -`gawk-4.1.1'. Like most GNU software, `gawk' is configured -automatically for your system by running the `configure' program. This -program is a Bourne shell script that is generated automatically using -GNU Autoconf. (The Autoconf software is described fully starting with -*note (Autoconf)Top:: autoconf,Autoconf--Generating Automatic -Configuration Scripts.) +`gawk-4.1.2'. As with most GNU software, you configure `gawk' for your +system by running the `configure' program. This program is a Bourne +shell script that is generated automatically using GNU Autoconf. (The +Autoconf software is described fully starting with *note +(Autoconf)Top:: autoconf,Autoconf--Generating Automatic Configuration +Scripts.) To configure `gawk', simply run `configure': @@ -27284,9 +27571,43 @@ will be asked for your password, and you will have to have been set up previously as a user who is allowed to run the `sudo' command. -File: gawk.info, Node: Additional Configuration Options, Next: Configuration Philosophy, Prev: Quick Installation, Up: Unix Installation +File: gawk.info, Node: Shell Startup Files, Next: Additional Configuration Options, Prev: Quick Installation, Up: Unix Installation + +B.2.2 Shell Startup Files +------------------------- + +The distribution contains shell startup files `gawk.sh' and `gawk.csh' +containing functions to aid in manipulating the `AWKPATH' and +`AWKLIBPATH' environment variables. On a Fedora system, these files +should be installed in `/etc/profile.d'; on other platforms, the +appropriate location may be different. -B.2.2 Additional Configuration Options +`gawkpath_default' + Reset the `AWKPATH' environment variable to its default value. + +`gawkpath_prepend' + Add the argument to the front of the `AWKPATH' environment + variable. + +`gawkpath_append' + Add the argument to the end of the `AWKPATH' environment variable. + +`gawklibpath_default' + Reset the `AWKLIBPATH' environment variable to its default value. + +`gawklibpath_prepend' + Add the argument to the front of the `AWKLIBPATH' environment + variable. + +`gawklibpath_append' + Add the argument to the end of the `AWKLIBPATH' environment + variable. + + + +File: gawk.info, Node: Additional Configuration Options, Next: Configuration Philosophy, Prev: Shell Startup Files, Up: Unix Installation + +B.2.3 Additional Configuration Options -------------------------------------- There are several additional options you may use on the `configure' @@ -27305,8 +27626,8 @@ command line when compiling `gawk' from scratch, including: User-modified::) has no effect on the running `awk' program. When used with GCC's automatic dead-code-elimination, this option - cuts almost 200K bytes off the size of the `gawk' executable on - GNU/Linux x86 systems. Results on other systems and with other + cuts almost 23K bytes off the size of the `gawk' executable on + GNU/Linux x86_64 systems. Results on other systems and with other compilers are likely to vary. Using this option may bring you some slight performance improvement. @@ -27328,7 +27649,7 @@ that `configure' supplies. File: gawk.info, Node: Configuration Philosophy, Prev: Additional Configuration Options, Up: Unix Installation -B.2.3 The Configuration Process +B.2.4 The Configuration Process ------------------------------- This minor node is of interest only if you know something about using @@ -27392,10 +27713,10 @@ File: gawk.info, Node: PC Installation, Next: VMS Installation, Up: Non-Unix B.3.1 Installation on PC Operating Systems ------------------------------------------ -This minor node covers installation and usage of `gawk' on x86 machines -running MS-DOS, any version of MS-Windows, or OS/2. In this minor -node, the term "Windows32" refers to any of Microsoft -Windows-95/98/ME/NT/2000/XP/Vista/7/8. +This minor node covers installation and usage of `gawk' on Intel +architecture machines running MS-DOS, any version of MS-Windows, or +OS/2. In this minor node, the term "Windows32" refers to any of +Microsoft Windows-95/98/ME/NT/2000/XP/Vista/7/8. The limitations of MS-DOS (and MS-DOS shells under the other operating systems) has meant that various "DOS extenders" are often @@ -27480,7 +27801,7 @@ MS-DOS and Windows32 versions. A list of targets is printed if the `gawk' using the DJGPP tools, enter `make djgpp'. (The DJGPP tools needed for the build may be found at `ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/'.) To build a native -MS-Windows binary of `gawk', type `make mingw32'. +MS-Windows binary of `gawk' using the MinGW tools, type `make mingw32'. The 32 bit EMX version of `gawk' works "out of the box" under OS/2. However, it is highly recommended to use GCC 2.95.3 for the compilation. @@ -27572,8 +27893,8 @@ Networking::). EMX (OS/2 only) supports at least the `|&' operator. The MS-DOS and MS-Windows versions of `gawk' search for program files as described in *note AWKPATH Variable::. However, semicolons (rather than colons) separate elements in the `AWKPATH' variable. If -`AWKPATH' is not set or is empty, then the default search path for -MS-Windows and MS-DOS versions is `.;c:/lib/awk;c:/gnu/lib/awk'. +`AWKPATH' is not set or is empty, then the default search path is +`.;c:/lib/awk;c:/gnu/lib/awk'. The search path for OS/2 (32 bit, EMX) is determined by the prefix directory (most likely `/usr' or `c:/usr') that has been specified as @@ -27597,10 +27918,10 @@ programs) silently translate end-of-line `\r\n' to `\n' on input and `\n' to `\r\n' on output. A special `BINMODE' variable (c.e.) allows control over these translations and is interpreted as follows: - * If `BINMODE' is `"r"', or one, then binary mode is set on read + * If `BINMODE' is `"r"' or one, then binary mode is set on read (i.e., no translations on reads). - * If `BINMODE' is `"w"', or two, then binary mode is set on write + * If `BINMODE' is `"w"' or two, then binary mode is set on write (i.e., no translations on writes). * If `BINMODE' is `"rw"' or `"wr"' or three, binary mode is set for @@ -27664,10 +27985,10 @@ GNU tools, such as Bash, the GNU Compiler Collection (GCC), GNU Make, and other GNU programs. Compilation and installation for Cygwin is the same as for a Unix system: - tar -xvpzf gawk-4.1.1.tar.gz - cd gawk-4.1.1 + tar -xvpzf gawk-4.1.2.tar.gz + cd gawk-4.1.2 ./configure - make + make && make check When compared to GNU/Linux on the same system, the `configure' step on Cygwin takes considerably longer. However, it does finish, and then @@ -27685,13 +28006,13 @@ use the `BINMODE' variable. This can cause problems with other Unix-like components that have been ported to MS-Windows that expect `gawk' to do automatic -translation of `"\r\n"', since it won't. Caveat Emptor! +translation of `"\r\n"', since it won't. File: gawk.info, Node: VMS Installation, Prev: PC Installation, Up: Non-Unix Installation -B.3.2 How to Compile and Install `gawk' on Vax/VMS and OpenVMS --------------------------------------------------------------- +B.3.2 Compiling and Installing `gawk' on Vax/VMS and OpenVMS +------------------------------------------------------------ This node describes how to compile and install `gawk' under VMS. The older designation "VMS" is used throughout to refer to OpenVMS. @@ -27781,7 +28102,7 @@ than 32 bits. /name=(as_is,short) Compile time macros need to be defined before the first VMS-supplied -header file is included. +header file is included, as follows: #if (__CRTL_VER >= 70200000) && !defined (__VAX) #define _LARGEFILE 1 @@ -27795,6 +28116,12 @@ header file is included. #endif #endif + If you are writing your own extensions to run on VMS, you must +supply these definitions yourself. The `config.h' file created when +building `gawk' on VMS does this for you; if instead you use that file +or a similar one, then you must remember to include it before any +VMS-supplied header files. + File: gawk.info, Node: VMS Installation Details, Next: VMS Running, Prev: VMS Dynamic Extensions, Up: VMS Installation @@ -27882,12 +28209,12 @@ If any other dash-type options (or multiple parameters such as data files to process) are present, there is no ambiguity and `--' can be omitted. - The `exit' value is a Unix-style value and is encoded to a VMS exit + The `exit' value is a Unix-style value and is encoded into a VMS exit status value when the program exits. The VMS severity bits will be set based on the `exit' value. A failure is indicated by 1 and VMS sets the `ERROR' status. A fatal -error is indicated by 2 and VMS will set the `FATAL' status. All other +error is indicated by 2 and VMS sets the `FATAL' status. All other values will have the `SUCCESS' status. The exit value is encoded to comply with VMS coding standards and will have the `C_FACILITY_NO' of `0x350000' with the constant `0xA000' added to the number shifted over @@ -27900,9 +28227,9 @@ by 3 bits to make room for the severity codes. A C program that uses `exec()' to call `gawk' will get the original Unix-style exit value. - Older versions of `gawk' treated a Unix exit code 0 as 1, a failure -as 2, a fatal error as 4, and passed all the other numbers through. -This violated the VMS exit status coding requirements. + Older versions of `gawk' for VMS treated a Unix exit code 0 as 1, a +failure as 2, a fatal error as 4, and passed all the other numbers +through. This violated the VMS exit status coding requirements. VAX/VMS floating point uses unbiased rounding. *Note Round Function::. @@ -27933,8 +28260,8 @@ reorganized to supply individual PCSI packages for each component. See The normal build procedure for `gawk' produces a program that is suitable for use with GNV. - The `vms/gawk_build_steps.txt' in the source documents the procedure -for building a VMS PCSI kit that is compatible with GNV. + The file `vms/gawk_build_steps.txt' in the distribution documents +the procedure for building a VMS PCSI kit that is compatible with GNV. File: gawk.info, Node: VMS Old Gawk, Prev: VMS GNV, Up: VMS Installation @@ -27963,10 +28290,10 @@ B.4 Reporting Problems and Bugs please report it to the developers; we cannot promise to do anything but we might well want to fix it. - Before reporting a bug, make sure you have actually found a real bug. -Carefully reread the documentation and see if it really says you can do -what you're trying to do. If it's not clear whether you should be able -to do something or not, report that too; it's a bug in the + Before reporting a bug, please make sure you have really found a +genuine bug. Carefully reread the documentation and see if it says you +can do what you're trying to do. If it's not clear whether you should +be able to do something or not, report that too; it's a bug in the documentation! Before reporting a bug or trying to fix it yourself, try to isolate @@ -27980,20 +28307,21 @@ really in the documentation. Please include the version number of `gawk' you are using. You can get this information with the command `gawk --version'. - Once you have a precise problem, send email to <bug-gawk@gnu.org>. + Once you have a precise problem description, send email to +<bug-gawk@gnu.org>. The `gawk' maintainers subscribe to this address and thus they will -receive your bug report. If necessary, the primary maintainer can be -reached directly at <arnold@skeeve.com>. The bug reporting address is -preferred since the email list is archived at the GNU Project. _All -email should be in English. This is the only language understood in -common by all the maintainers._ +receive your bug report. Although you can send mail to the maintainers +directly, the bug reporting address is preferred since the email list +is archived at the GNU Project. _All email must be in English. This is +the only language understood in common by all the maintainers._ CAUTION: Do _not_ try to report bugs in `gawk' by posting to the Usenet/Internet newsgroup `comp.lang.awk'. While the `gawk' developers do occasionally read this newsgroup, there is no guarantee that we will see your posting. The steps described - above are the official recognized ways for reporting bugs. Really. + above are the only official recognized way for reporting bugs. + Really. NOTE: Many distributions of GNU/Linux and the various BSD-based operating systems have their own bug reporting systems. If you @@ -28002,30 +28330,30 @@ common by all the maintainers._ This is for two reasons. First, while some distributions forward bug reports "upstream" to the GNU mailing list, many don't, so - there is a good chance that the `gawk' maintainer won't even see + there is a good chance that the `gawk' maintainers won't even see the bug report! Second, mail to the GNU list is archived, and having everything at the GNU project keeps things self-contained - and not dependant on other web sites. + and not dependant on other organizations. Non-bug suggestions are always welcome as well. If you have questions about things that are unclear in the documentation or are -just obscure features, ask me; I will try to help you out, although I -may not have the time to fix the problem. You can send me electronic -mail at the Internet address noted previously. +just obscure features, ask on the bug list; we will try to help you out +if we can. If you find bugs in one of the non-Unix ports of `gawk', please send -an electronic mail message to the person who maintains that port. They -are named in the following list, as well as in the `README' file in the -`gawk' distribution. Information in the `README' file should be -considered authoritative if it conflicts with this Info file. +an electronic mail message to the bug list, with a copy to the person +who maintains that port. They are named in the following list, as well +as in the `README' file in the `gawk' distribution. Information in the +`README' file should be considered authoritative if it conflicts with +this Info file. - The people maintaining the non-Unix ports of `gawk' are as follows: + The people maintaining the various `gawk' ports are: +Unix and POSIX systems Arnold Robbins, <arnold@skeeve.com>. MS-DOS with DJGPP Scott Deifik, <scottd.mail@sbcglobal.net>. MS-Windows with MinGW Eli Zaretskii, <eliz@gnu.org>. OS/2 Andreas Buening, <andreas.buening@nexgo.de>. -VMS Pat Rankin, <r.pat.rankin@gmail.com>, and John - Malmberg, <wb8tyw@qsl.net>. +VMS John Malmberg, <wb8tyw@qsl.net>. z/OS (OS/390) Dave Pitts, <dpitts@cozx.com>. If your bug is also reproducible under Unix, please send a copy of @@ -28112,9 +28440,9 @@ Unix `awk' `pawk' Nelson H.F. Beebe at the University of Utah has modified BWK `awk' to provide timing and profiling information. It is different from - `gawk' with the `--profile' option. (*note Profiling::), in that - it uses CPU-based profiling, not line-count profiling. You may - find it at either + `gawk' with the `--profile' option (*note Profiling::), in that it + uses CPU-based profiling, not line-count profiling. You may find + it at either `ftp://ftp.math.utah.edu/pub/pawk/pawk-20030606.tar.gz' or `http://www.math.utah.edu/pub/pawk/pawk-20030606.tar.gz'. @@ -28130,11 +28458,11 @@ Busybox Awk The OpenSolaris POSIX `awk' The versions of `awk' in `/usr/xpg4/bin' and `/usr/xpg6/bin' on Solaris are more-or-less POSIX-compliant. They are based on the - `awk' from Mortice Kern Systems for PCs. This author was able to - make this code compile and work under GNU/Linux with 1-2 hours of - work. Making it more generally portable (using GNU Autoconf - and/or Automake) would take more work, and this has not been done, - at least to our knowledge. + `awk' from Mortice Kern Systems for PCs. We were able to make + this code compile and work under GNU/Linux with 1-2 hours of work. + Making it more generally portable (using GNU Autoconf and/or + Automake) would take more work, and this has not been done, at + least to our knowledge. The source code used to be available from the OpenSolaris web site. However, that project was ended and the web site shut down. @@ -28190,9 +28518,9 @@ B.6 Summary * The `gawk' distribution is available from GNU project's main distribution site, `ftp.gnu.org'. The canonical build recipe is: - wget http://ftp.gnu.org/gnu/gawk/gawk-4.1.1.tar.gz - tar -xvpzf gawk-4.1.1.tar.gz - cd gawk-4.1.1 + wget http://ftp.gnu.org/gnu/gawk/gawk-4.1.2.tar.gz + tar -xvpzf gawk-4.1.2.tar.gz + cd gawk-4.1.2 ./configure && make && make check * `gawk' may be built on non-POSIX systems as well. The currently @@ -28323,9 +28651,9 @@ there are several steps that you need to take in order to make it possible to include them: 1. Before building the new feature into `gawk' itself, consider - writing it as an extension module (*note Dynamic Extensions::). - If that's not possible, continue with the rest of the steps in - this list. + writing it as an extension (*note Dynamic Extensions::). If + that's not possible, continue with the rest of the steps in this + list. 2. Be prepared to sign the appropriate paperwork. In order for the FSF to distribute your changes, you must either place those @@ -28492,9 +28820,9 @@ steps: 6. Be willing to continue to maintain the port. Non-Unix operating systems are supported by volunteers who maintain the code needed - to compile and run `gawk' on their systems. If noone volunteers to - maintain a port, it becomes unsupported and it may be necessary to - remove it from the distribution. + to compile and run `gawk' on their systems. If no-one volunteers + to maintain a port, it becomes unsupported and it may be necessary + to remove it from the distribution. 7. Supply an appropriate `gawkmisc.???' file. Each port has its own `gawkmisc.???' that implements certain operating system specific @@ -28881,7 +29209,7 @@ C.5.3 Other Design Decisions ---------------------------- As an arbitrary design decision, extensions can read the values of -built-in variables and arrays (such as `ARGV' and `FS'), but cannot +predefined variables and arrays (such as `ARGV' and `FS'), but cannot change them, with the exception of `PROCINFO'. The reason for this is to prevent an extension function from @@ -29288,6 +29616,10 @@ Bourne Shell shells (Bash, `ksh', `pdksh', `zsh') are generally upwardly compatible with the Bourne shell. +Braces + The characters `{' and `}'. Braces are used in `awk' for + delimiting actions, compound statements, and function bodies. + Built-in Function The `awk' language provides built-in functions that perform various numerical, I/O-related, and string computations. Examples are @@ -29306,10 +29638,6 @@ Built-in Variable them affects `awk''s running environment. (*Note Built-in Variables::.) -Braces - The characters `{' and `}'. Braces are used in `awk' for - delimiting actions, compound statements, and function bodies. - C The system programming language that most GNU software is written in. The `awk' programming language has C-like syntax, and this @@ -29448,11 +29776,11 @@ FDL Field When `awk' reads an input record, it splits the record into pieces separated by whitespace (or by a separator regexp that you can - change by setting the built-in variable `FS'). Such pieces are + change by setting the predefined variable `FS'). Such pieces are called fields. If the pieces are of fixed length, you can use the built-in variable `FIELDWIDTHS' to describe their lengths. If you wish to specify the contents of fields instead of the field - separator, you can use the built-in variable `FPAT' to do so. + separator, you can use the predefined variable `FPAT' to do so. (*Note Field Separators::, *note Constant Size::, and *note Splitting By Content::.) @@ -29469,7 +29797,7 @@ Format Format strings control the appearance of output in the `strftime()' and `sprintf()' functions, and in the `printf' statement as well. Also, data conversions from numbers to strings - are controlled by the format strings contained in the built-in + are controlled by the format strings contained in the predefined variables `CONVFMT' and `OFMT'. (*Note Control Letters::.) Free Documentation License @@ -31036,7 +31364,7 @@ Index * Menu: -* ! (exclamation point), ! operator: Boolean Ops. (line 67) +* ! (exclamation point), ! operator: Boolean Ops. (line 69) * ! (exclamation point), ! operator <1>: Egrep Program. (line 175) * ! (exclamation point), ! operator <2>: Ranges. (line 48) * ! (exclamation point), ! operator: Precedence. (line 52) @@ -31066,22 +31394,22 @@ Index * % (percent sign), %= operator <1>: Precedence. (line 95) * % (percent sign), %= operator: Assignment Ops. (line 130) * & (ampersand), && operator <1>: Precedence. (line 86) -* & (ampersand), && operator: Boolean Ops. (line 57) +* & (ampersand), && operator: Boolean Ops. (line 59) * & (ampersand), gsub()/gensub()/sub() functions and: Gory Details. (line 6) * ' (single quote): One-shot. (line 15) -* ' (single quote) in gawk command lines: Long. (line 33) +* ' (single quote) in gawk command lines: Long. (line 35) * ' (single quote), in shell commands: Quoting. (line 48) * ' (single quote), vs. apostrophe: Comments. (line 27) -* ' (single quote), with double quotes: Quoting. (line 70) +* ' (single quote), with double quotes: Quoting. (line 73) * () (parentheses), in a profile: Profiling. (line 146) * () (parentheses), regexp operator: Regexp Operators. (line 81) * * (asterisk), * operator, as multiplication operator: Precedence. (line 55) * * (asterisk), * operator, as regexp operator: Regexp Operators. (line 89) -* * (asterisk), * operator, null strings, matching: Gory Details. - (line 143) +* * (asterisk), * operator, null strings, matching: String Functions. + (line 535) * * (asterisk), ** operator <1>: Precedence. (line 49) * * (asterisk), ** operator: Arithmetic Ops. (line 81) * * (asterisk), **= operator <1>: Precedence. (line 95) @@ -31125,30 +31453,30 @@ Index * --include option: Options. (line 159) * --lint option <1>: Options. (line 185) * --lint option: Command Line. (line 20) -* --lint-old option: Options. (line 293) +* --lint-old option: Options. (line 295) * --load option: Options. (line 173) * --non-decimal-data option <1>: Nondecimal Data. (line 6) * --non-decimal-data option: Options. (line 211) * --non-decimal-data option, strtonum() function and: Nondecimal Data. - (line 36) -* --optimize option: Options. (line 235) -* --posix option: Options. (line 252) -* --posix option, --traditional option and: Options. (line 271) -* --pretty-print option: Options. (line 224) + (line 35) +* --optimize option: Options. (line 237) +* --posix option: Options. (line 254) +* --posix option, --traditional option and: Options. (line 273) +* --pretty-print option: Options. (line 226) * --profile option <1>: Profiling. (line 12) -* --profile option: Options. (line 240) -* --re-interval option: Options. (line 277) -* --sandbox option: Options. (line 284) +* --profile option: Options. (line 242) +* --re-interval option: Options. (line 279) +* --sandbox option: Options. (line 286) * --sandbox option, disabling system() function: I/O Functions. - (line 97) + (line 96) * --sandbox option, input redirection with getline: Getline. (line 19) * --sandbox option, output redirection with print, printf: Redirection. (line 6) * --source option: Options. (line 117) * --traditional option: Options. (line 81) -* --traditional option, --posix option and: Options. (line 271) -* --use-lc-numeric option: Options. (line 219) -* --version option: Options. (line 298) +* --traditional option, --posix option and: Options. (line 273) +* --use-lc-numeric option: Options. (line 221) +* --version option: Options. (line 300) * --with-whiny-user-strftime configuration option: Additional Configuration Options. (line 35) * -b option: Options. (line 68) @@ -31156,42 +31484,42 @@ Index * -c option: Options. (line 81) * -D option: Options. (line 108) * -d option: Options. (line 93) -* -e option: Options. (line 333) +* -e option: Options. (line 336) * -E option: Options. (line 125) * -e option: Options. (line 117) * -f option: Options. (line 25) * -F option: Options. (line 21) * -f option: Long. (line 12) -* -F option, -Ft sets FS to TAB: Options. (line 306) +* -F option, -Ft sets FS to TAB: Options. (line 308) * -F option, command-line: Command Line Field Separator. (line 6) -* -f option, multiple uses: Options. (line 311) +* -f option, multiple uses: Options. (line 313) * -g option: Options. (line 147) * -h option: Options. (line 154) * -i option: Options. (line 159) -* -L option: Options. (line 293) +* -L option: Options. (line 295) * -l option: Options. (line 173) * -M option: Options. (line 205) -* -N option: Options. (line 219) +* -N option: Options. (line 221) * -n option: Options. (line 211) -* -O option: Options. (line 235) -* -o option: Options. (line 224) -* -P option: Options. (line 252) -* -p option: Options. (line 240) -* -r option: Options. (line 277) -* -S option: Options. (line 284) +* -O option: Options. (line 237) +* -o option: Options. (line 226) +* -P option: Options. (line 254) +* -p option: Options. (line 242) +* -r option: Options. (line 279) +* -S option: Options. (line 286) * -v option: Assignment Options. (line 12) -* -V option: Options. (line 298) +* -V option: Options. (line 300) * -v option: Options. (line 32) * -W option: Options. (line 46) * . (period), regexp operator: Regexp Operators. (line 44) * .gmo files: Explaining gettext. (line 42) * .gmo files, specifying directory of <1>: Programmer i18n. (line 47) * .gmo files, specifying directory of: Explaining gettext. (line 54) -* .mo files, converting from .po: I18N Example. (line 63) +* .mo files, converting from .po: I18N Example. (line 64) * .po files <1>: Translator i18n. (line 6) * .po files: Explaining gettext. (line 37) -* .po files, converting to .mo: I18N Example. (line 63) +* .po files, converting to .mo: I18N Example. (line 64) * .pot files: Explaining gettext. (line 31) * / (forward slash) to enclose regular expressions: Regexp. (line 10) * / (forward slash), / operator: Precedence. (line 55) @@ -31201,8 +31529,8 @@ Index (line 148) * / (forward slash), patterns and: Expression Patterns. (line 24) * /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) -* /dev/... special files: Special FD. (line 46) -* /dev/fd/N special files (gawk): Special FD. (line 46) +* /dev/... special files: Special FD. (line 48) +* /dev/fd/N special files (gawk): Special FD. (line 48) * /inet/... special files (gawk): TCP/IP Networking. (line 6) * /inet4/... special files (gawk): TCP/IP Networking. (line 6) * /inet6/... special files (gawk): TCP/IP Networking. (line 6) @@ -31243,10 +31571,10 @@ Index (line 8) * [] (square brackets), regexp operator: Regexp Operators. (line 56) * \ (backslash): Comments. (line 50) -* \ (backslash), \" escape sequence: Escape Sequences. (line 84) +* \ (backslash), \" escape sequence: Escape Sequences. (line 85) * \ (backslash), \' operator (gawk): GNU Regexp Operators. (line 56) -* \ (backslash), \/ escape sequence: Escape Sequences. (line 75) +* \ (backslash), \/ escape sequence: Escape Sequences. (line 76) * \ (backslash), \< operator (gawk): GNU Regexp Operators. (line 30) * \ (backslash), \> operator (gawk): GNU Regexp Operators. @@ -31275,7 +31603,7 @@ Index * \ (backslash), \y operator (gawk): GNU Regexp Operators. (line 38) * \ (backslash), as field separator: Command Line Field Separator. - (line 27) + (line 24) * \ (backslash), continuing lines and: Statements/Lines. (line 19) * \ (backslash), continuing lines and, comments and: Statements/Lines. (line 76) @@ -31286,7 +31614,7 @@ Index * \ (backslash), in bracket expressions: Bracket Expressions. (line 17) * \ (backslash), in escape sequences: Escape Sequences. (line 6) * \ (backslash), in escape sequences, POSIX and: Escape Sequences. - (line 120) + (line 121) * \ (backslash), in regexp constants: Computed Regexps. (line 29) * \ (backslash), in shell commands: Quoting. (line 48) * \ (backslash), regexp operator: Regexp Operators. (line 18) @@ -31338,12 +31666,12 @@ Index * ambiguity, syntactic: /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) * ampersand (&), && operator <1>: Precedence. (line 86) -* ampersand (&), && operator: Boolean Ops. (line 57) +* ampersand (&), && operator: Boolean Ops. (line 59) * ampersand (&), gsub()/gensub()/sub() functions and: Gory Details. (line 6) -* anagram.awk program: Anagram Program. (line 22) +* anagram.awk program: Anagram Program. (line 21) * anagrams, finding: Anagram Program. (line 6) -* and: Bitwise Functions. (line 39) +* and: Bitwise Functions. (line 40) * AND bitwise operation: Bitwise Functions. (line 6) * and Boolean-logic operator: Boolean Ops. (line 6) * ANSI: Glossary. (line 34) @@ -31359,25 +31687,25 @@ Index * arctangent: Numeric Functions. (line 11) * ARGC/ARGV variables: Auto-set. (line 15) * ARGC/ARGV variables, command-line arguments: Other Arguments. - (line 12) + (line 15) * ARGC/ARGV variables, how to use: ARGC and ARGV. (line 6) * ARGC/ARGV variables, portability and: Executable Scripts. (line 59) * ARGIND variable: Auto-set. (line 44) -* ARGIND variable, command-line arguments: Other Arguments. (line 12) +* ARGIND variable, command-line arguments: Other Arguments. (line 15) * arguments, command-line <1>: ARGC and ARGV. (line 6) * arguments, command-line <2>: Auto-set. (line 15) * arguments, command-line: Other Arguments. (line 6) * arguments, command-line, invoking awk: Command Line. (line 6) * arguments, in function calls: Function Calls. (line 18) * arguments, processing: Getopt Function. (line 6) -* ARGV array, indexing into: Other Arguments. (line 12) +* ARGV array, indexing into: Other Arguments. (line 15) * arithmetic operators: Arithmetic Ops. (line 6) * array manipulation in extensions: Array Manipulation. (line 6) * array members: Reference to Elements. (line 6) * array scanning order, controlling: Controlling Scanning. (line 14) -* array, number of elements: String Functions. (line 197) +* array, number of elements: String Functions. (line 200) * arrays: Arrays. (line 6) * arrays of arrays: Arrays of Arrays. (line 6) * arrays, an example of using: Array Example. (line 6) @@ -31385,7 +31713,7 @@ Index * arrays, as parameters to functions: Pass By Value/Reference. (line 47) * arrays, associative: Array Intro. (line 50) -* arrays, associative, library functions and: Library Names. (line 57) +* arrays, associative, library functions and: Library Names. (line 58) * arrays, deleting entire contents: Delete. (line 39) * arrays, elements that don't exist: Reference to Elements. (line 23) @@ -31393,13 +31721,12 @@ Index * arrays, elements, deleting: Delete. (line 6) * arrays, elements, order of access by in operator: Scanning an Array. (line 48) -* arrays, elements, retrieving number of: String Functions. (line 42) +* arrays, elements, retrieving number of: String Functions. (line 41) * arrays, for statement and: Scanning an Array. (line 20) * arrays, indexing: Array Intro. (line 50) * arrays, merging into strings: Join Function. (line 6) * arrays, multidimensional: Multidimensional. (line 10) * arrays, multidimensional, scanning: Multiscanning. (line 11) -* arrays, names of, and names of functions/variables: Arrays. (line 18) * arrays, numeric subscripts: Numeric Array Subscripts. (line 6) * arrays, referencing elements: Reference to Elements. @@ -31420,12 +31747,12 @@ Index * ASCII: Ordinal Functions. (line 45) * asort <1>: Array Sorting Functions. (line 6) -* asort: String Functions. (line 42) +* asort: String Functions. (line 41) * asort() function (gawk), arrays, sorting: Array Sorting Functions. (line 6) * asorti <1>: Array Sorting Functions. (line 6) -* asorti: String Functions. (line 42) +* asorti: String Functions. (line 41) * asorti() function (gawk), arrays, sorting: Array Sorting Functions. (line 6) * assert() function (C library): Assert Function. (line 6) @@ -31442,8 +31769,8 @@ Index (line 55) * asterisk (*), * operator, as regexp operator: Regexp Operators. (line 89) -* asterisk (*), * operator, null strings, matching: Gory Details. - (line 143) +* asterisk (*), * operator, null strings, matching: String Functions. + (line 535) * asterisk (*), ** operator <1>: Precedence. (line 49) * asterisk (*), ** operator: Arithmetic Ops. (line 81) * asterisk (*), **= operator <1>: Precedence. (line 95) @@ -31455,7 +31782,7 @@ Index * awf (amazingly workable formatter) program: Glossary. (line 24) * awk debugging, enabling: Options. (line 108) * awk language, POSIX version: Assignment Ops. (line 137) -* awk profiling, enabling: Options. (line 240) +* awk profiling, enabling: Options. (line 242) * awk programs <1>: Two Rules. (line 6) * awk programs <2>: Executable Scripts. (line 6) * awk programs: Getting Started. (line 12) @@ -31481,7 +31808,7 @@ Index * awk, gawk and <1>: This Manual. (line 14) * awk, gawk and: Preface. (line 21) * awk, history of: History. (line 17) -* awk, implementation issues, pipes: Redirection. (line 135) +* awk, implementation issues, pipes: Redirection. (line 129) * awk, implementations: Other Versions. (line 6) * awk, implementations, limits: Getline Notes. (line 14) * awk, invoking: Command Line. (line 6) @@ -31490,7 +31817,7 @@ Index * awk, POSIX and: Preface. (line 21) * awk, POSIX and, See Also POSIX awk: Preface. (line 21) * awk, regexp constants and: Comparison Operators. - (line 102) + (line 103) * awk, See Also gawk: Preface. (line 34) * awk, terms describing: This Manual. (line 6) * awk, uses for <1>: When. (line 6) @@ -31513,10 +31840,10 @@ Index * awkvars.out file: Options. (line 93) * b debugger command (alias for break): Breakpoint Control. (line 11) * backslash (\): Comments. (line 50) -* backslash (\), \" escape sequence: Escape Sequences. (line 84) +* backslash (\), \" escape sequence: Escape Sequences. (line 85) * backslash (\), \' operator (gawk): GNU Regexp Operators. (line 56) -* backslash (\), \/ escape sequence: Escape Sequences. (line 75) +* backslash (\), \/ escape sequence: Escape Sequences. (line 76) * backslash (\), \< operator (gawk): GNU Regexp Operators. (line 30) * backslash (\), \> operator (gawk): GNU Regexp Operators. @@ -31545,7 +31872,7 @@ Index * backslash (\), \y operator (gawk): GNU Regexp Operators. (line 38) * backslash (\), as field separator: Command Line Field Separator. - (line 27) + (line 24) * backslash (\), continuing lines and: Statements/Lines. (line 19) * backslash (\), continuing lines and, comments and: Statements/Lines. (line 76) @@ -31556,7 +31883,7 @@ Index * backslash (\), in bracket expressions: Bracket Expressions. (line 17) * backslash (\), in escape sequences: Escape Sequences. (line 6) * backslash (\), in escape sequences, POSIX and: Escape Sequences. - (line 120) + (line 121) * backslash (\), in regexp constants: Computed Regexps. (line 29) * backslash (\), in shell commands: Quoting. (line 48) * backslash (\), regexp operator: Regexp Operators. (line 18) @@ -31576,18 +31903,18 @@ Index * BEGIN pattern, next/nextfile statements and <1>: Next Statement. (line 44) * BEGIN pattern, next/nextfile statements and: I/O And BEGIN/END. - (line 36) + (line 37) * BEGIN pattern, OFS/ORS variables, assigning values to: Output Separators. (line 20) * BEGIN pattern, operators and: Using BEGIN/END. (line 17) * BEGIN pattern, print statement and: I/O And BEGIN/END. (line 16) * BEGIN pattern, pwcat program: Passwd Functions. (line 143) -* BEGIN pattern, running awk programs and: Cut Program. (line 68) +* BEGIN pattern, running awk programs and: Cut Program. (line 63) * BEGIN pattern, TEXTDOMAIN variable and: Programmer i18n. (line 60) * BEGINFILE pattern: BEGINFILE/ENDFILE. (line 6) * BEGINFILE pattern, Boolean patterns and: Expression Patterns. (line 70) -* beginfile() user-defined function: Filetrans Function. (line 62) +* beginfile() user-defined function: Filetrans Function. (line 61) * Bentley, Jon: Glossary. (line 143) * Benzinger, Michael: Contributors. (line 97) * Berry, Karl <1>: Ranges and Locales. (line 74) @@ -31601,11 +31928,11 @@ Index * BINMODE variable <1>: PC Using. (line 33) * BINMODE variable: User-modified. (line 15) * bit-manipulation functions: Bitwise Functions. (line 6) -* bits2str() user-defined function: Bitwise Functions. (line 70) -* bitwise AND: Bitwise Functions. (line 39) -* bitwise complement: Bitwise Functions. (line 43) -* bitwise OR: Bitwise Functions. (line 49) -* bitwise XOR: Bitwise Functions. (line 55) +* bits2str() user-defined function: Bitwise Functions. (line 71) +* bitwise AND: Bitwise Functions. (line 40) +* bitwise complement: Bitwise Functions. (line 44) +* bitwise OR: Bitwise Functions. (line 50) +* bitwise XOR: Bitwise Functions. (line 56) * bitwise, complement: Bitwise Functions. (line 25) * bitwise, operations: Bitwise Functions. (line 6) * bitwise, shift: Bitwise Functions. (line 32) @@ -31645,12 +31972,13 @@ Index * Brennan, Michael <1>: Other Versions. (line 6) * Brennan, Michael <2>: Simple Sed. (line 25) * Brennan, Michael <3>: Delete. (line 56) -* Brennan, Michael <4>: Acknowledgments. (line 76) -* Brennan, Michael: Foreword. (line 83) +* Brennan, Michael <4>: Acknowledgments. (line 78) +* Brennan, Michael <5>: Foreword4. (line 30) +* Brennan, Michael: Foreword3. (line 83) * Brian Kernighan's awk <1>: I/O Functions. (line 43) * Brian Kernighan's awk <2>: Gory Details. (line 19) -* Brian Kernighan's awk <3>: String Functions. (line 490) -* Brian Kernighan's awk <4>: Delete. (line 48) +* Brian Kernighan's awk <3>: String Functions. (line 491) +* Brian Kernighan's awk <4>: Delete. (line 51) * Brian Kernighan's awk <5>: Nextfile Statement. (line 47) * Brian Kernighan's awk <6>: Continue Statement. (line 44) * Brian Kernighan's awk <7>: Break Statement. (line 51) @@ -31661,7 +31989,7 @@ Index (line 67) * Brian Kernighan's awk <12>: GNU Regexp Operators. (line 83) -* Brian Kernighan's awk <13>: Escape Sequences. (line 124) +* Brian Kernighan's awk <13>: Escape Sequences. (line 125) * Brian Kernighan's awk: When. (line 21) * Brian Kernighan's awk, extensions: BTL. (line 6) * Brian Kernighan's awk, source code: Other Versions. (line 13) @@ -31671,12 +31999,12 @@ Index * Brown, Martin: Contributors. (line 82) * BSD-based operating systems: Glossary. (line 611) * bt debugger command (alias for backtrace): Execution Stack. (line 13) -* Buening, Andreas <1>: Bugs. (line 71) +* Buening, Andreas <1>: Bugs. (line 72) * Buening, Andreas <2>: Contributors. (line 92) * Buening, Andreas: Acknowledgments. (line 60) * buffering, input/output <1>: Two-way I/O. (line 52) -* buffering, input/output: I/O Functions. (line 140) -* buffering, interactive vs. noninteractive: I/O Functions. (line 109) +* buffering, input/output: I/O Functions. (line 139) +* buffering, interactive vs. noninteractive: I/O Functions. (line 108) * buffers, flushing: I/O Functions. (line 32) * buffers, operators for: GNU Regexp Operators. (line 48) @@ -31684,10 +32012,6 @@ Index * bug-gawk@gnu.org bug reporting address: Bugs. (line 30) * built-in functions: Functions. (line 6) * built-in functions, evaluation order: Calling Built-in. (line 30) -* built-in variables: Built-in Variables. (line 6) -* built-in variables, -v option, setting with: Options. (line 40) -* built-in variables, conveying information: Auto-set. (line 6) -* built-in variables, user-modifiable: User-modified. (line 6) * Busybox Awk: Other Versions. (line 88) * c.e., See common extensions: Conventions. (line 51) * call by reference: Pass By Value/Reference. @@ -31706,7 +32030,7 @@ Index * case sensitivity, and regexps: User-modified. (line 76) * case sensitivity, and string comparisons: User-modified. (line 76) * case sensitivity, array indices and: Array Intro. (line 94) -* case sensitivity, converting case: String Functions. (line 520) +* case sensitivity, converting case: String Functions. (line 521) * case sensitivity, example programs: Library Functions. (line 53) * case sensitivity, gawk: Case-sensitivity. (line 26) * case sensitivity, regexps and: Case-sensitivity. (line 6) @@ -31742,14 +32066,14 @@ Index * close() function, portability: Close Files And Pipes. (line 81) * close() function, return value: Close Files And Pipes. - (line 131) + (line 132) * close() function, two-way pipes and: Two-way I/O. (line 59) * Close, Diane <1>: Contributors. (line 20) * Close, Diane: Manual History. (line 34) * Collado, Manuel: Acknowledgments. (line 60) * collating elements: Bracket Expressions. (line 79) * collating symbols: Bracket Expressions. (line 86) -* Colombo, Antonio <1>: Contributors. (line 137) +* Colombo, Antonio <1>: Contributors. (line 140) * Colombo, Antonio: Acknowledgments. (line 60) * columns, aligning: Print Examples. (line 70) * columns, cutting: Cut Program. (line 6) @@ -31778,15 +32102,15 @@ Index * commenting, backslash continuation and: Statements/Lines. (line 76) * common extensions, ** operator: Arithmetic Ops. (line 30) * common extensions, **= operator: Assignment Ops. (line 137) -* common extensions, /dev/stderr special file: Special FD. (line 46) -* common extensions, /dev/stdin special file: Special FD. (line 46) -* common extensions, /dev/stdout special file: Special FD. (line 46) +* common extensions, /dev/stderr special file: Special FD. (line 48) +* common extensions, /dev/stdin special file: Special FD. (line 48) +* common extensions, /dev/stdout special file: Special FD. (line 48) * common extensions, \x escape sequence: Escape Sequences. (line 61) * common extensions, BINMODE variable: PC Using. (line 33) * common extensions, delete to delete entire arrays: Delete. (line 39) * common extensions, func keyword: Definition Syntax. (line 93) * common extensions, length() applied to an array: String Functions. - (line 197) + (line 200) * common extensions, RS as a regexp: gawk split records. (line 6) * common extensions, single character fields: Single Character Fields. (line 6) @@ -31795,7 +32119,7 @@ Index (line 9) * comparison expressions, as patterns: Expression Patterns. (line 14) * comparison expressions, string vs. regexp: Comparison Operators. - (line 78) + (line 79) * compatibility mode (gawk), extensions: POSIX/GNU. (line 6) * compatibility mode (gawk), file names: Special Caveats. (line 9) * compatibility mode (gawk), hexadecimal numbers: Nondecimal-numbers. @@ -31809,7 +32133,7 @@ Index * compiling gawk for MS-DOS and MS-Windows: PC Compiling. (line 13) * compiling gawk for VMS: VMS Compilation. (line 6) * compiling gawk with EMX for OS/2: PC Compiling. (line 28) -* compl: Bitwise Functions. (line 43) +* compl: Bitwise Functions. (line 44) * complement, bitwise: Bitwise Functions. (line 25) * compound statements, control statements and: Statements. (line 10) * concatenating: Concatenation. (line 8) @@ -31835,15 +32159,15 @@ Index * control statements: Statements. (line 6) * controlling array scanning order: Controlling Scanning. (line 14) -* convert string to lower case: String Functions. (line 521) -* convert string to number: String Functions. (line 388) -* convert string to upper case: String Functions. (line 527) +* convert string to lower case: String Functions. (line 522) +* convert string to number: String Functions. (line 389) +* convert string to upper case: String Functions. (line 528) * converting integer array subscripts: Numeric Array Subscripts. (line 31) * converting, dates to timestamps: Time Functions. (line 76) -* converting, numbers to strings <1>: Bitwise Functions. (line 109) +* converting, numbers to strings <1>: Bitwise Functions. (line 110) * converting, numbers to strings: Strings And Numbers. (line 6) -* converting, strings to numbers <1>: Bitwise Functions. (line 109) +* converting, strings to numbers <1>: Bitwise Functions. (line 110) * converting, strings to numbers: Strings And Numbers. (line 6) * CONVFMT variable <1>: User-modified. (line 30) * CONVFMT variable: Strings And Numbers. (line 29) @@ -31851,7 +32175,7 @@ Index (line 6) * cookie: Glossary. (line 149) * coprocesses <1>: Two-way I/O. (line 25) -* coprocesses: Redirection. (line 102) +* coprocesses: Redirection. (line 96) * coprocesses, closing: Close Files And Pipes. (line 6) * coprocesses, getline from: Getline/Coprocess. (line 6) @@ -31859,7 +32183,7 @@ Index * cosine: Numeric Functions. (line 15) * counting: Wc Program. (line 6) * csh utility: Statements/Lines. (line 44) -* csh utility, POSIXLY_CORRECT environment variable: Options. (line 351) +* csh utility, POSIXLY_CORRECT environment variable: Options. (line 354) * csh utility, |& operator, comparison with: Two-way I/O. (line 25) * ctime() user-defined function: Function Example. (line 74) * currency symbols, localization: Explaining gettext. (line 104) @@ -31884,37 +32208,39 @@ Index (line 43) * dark corner, break statement: Break Statement. (line 51) * dark corner, close() function: Close Files And Pipes. - (line 131) + (line 132) * dark corner, command-line arguments: Assignment Options. (line 43) * dark corner, continue statement: Continue Statement. (line 44) * dark corner, CONVFMT variable: Strings And Numbers. (line 40) -* dark corner, escape sequences: Other Arguments. (line 35) +* dark corner, escape sequences: Other Arguments. (line 38) * dark corner, escape sequences, for metacharacters: Escape Sequences. - (line 142) + (line 143) * dark corner, exit statement: Exit Statement. (line 30) * dark corner, field separators: Field Splitting Summary. (line 46) * dark corner, FILENAME variable <1>: Auto-set. (line 98) * dark corner, FILENAME variable: Getline Notes. (line 19) -* dark corner, FNR/NR variables: Auto-set. (line 316) +* dark corner, FNR/NR variables: Auto-set. (line 321) * dark corner, format-control characters: Control Letters. (line 18) * dark corner, FS as null string: Single Character Fields. (line 20) -* dark corner, input files: awk split records. (line 110) +* dark corner, input files: awk split records. (line 111) * dark corner, invoking awk: Command Line. (line 16) -* dark corner, length() function: String Functions. (line 183) +* dark corner, length() function: String Functions. (line 186) * dark corner, locale's decimal point character: Locale influences conversions. (line 17) * dark corner, multiline records: Multiple Line. (line 35) * dark corner, NF variable, decrementing: Changing Fields. (line 107) * dark corner, OFMT variable: OFMT. (line 27) +* dark corner, regexp as second argument to index(): String Functions. + (line 164) * dark corner, regexp constants: Using Constant Regexps. (line 6) * dark corner, regexp constants, /= operator and: Assignment Ops. (line 148) * dark corner, regexp constants, as arguments to user-defined functions: Using Constant Regexps. (line 43) -* dark corner, split() function: String Functions. (line 359) +* dark corner, split() function: String Functions. (line 360) * dark corner, strings, storing: gawk split records. (line 83) * dark corner, value of ARGV[0]: Auto-set. (line 39) * data, fixed-width: Constant Size. (line 10) @@ -31928,7 +32254,7 @@ Index (line 112) * Davies, Stephen <1>: Contributors. (line 74) * Davies, Stephen: Acknowledgments. (line 60) -* Day, Robert P.J.: Acknowledgments. (line 76) +* Day, Robert P.J.: Acknowledgments. (line 78) * dcgettext <1>: Programmer i18n. (line 19) * dcgettext: I18N Functions. (line 22) * dcgettext() function (gawk), portability and: I18N Portability. @@ -31955,7 +32281,7 @@ Index * debugger commands, disable: Breakpoint Control. (line 69) * debugger commands, display: Viewing And Changing Data. (line 8) -* debugger commands, down: Execution Stack. (line 21) +* debugger commands, down: Execution Stack. (line 23) * debugger commands, dump: Miscellaneous Debugger Commands. (line 9) * debugger commands, e (enable): Breakpoint Control. (line 73) @@ -31964,10 +32290,10 @@ Index (line 10) * debugger commands, eval: Viewing And Changing Data. (line 23) -* debugger commands, f (frame): Execution Stack. (line 25) +* debugger commands, f (frame): Execution Stack. (line 27) * debugger commands, finish: Debugger Execution Control. (line 39) -* debugger commands, frame: Execution Stack. (line 25) +* debugger commands, frame: Execution Stack. (line 27) * debugger commands, h (help): Miscellaneous Debugger Commands. (line 66) * debugger commands, help: Miscellaneous Debugger Commands. @@ -32029,11 +32355,12 @@ Index (line 83) * debugger commands, unwatch: Viewing And Changing Data. (line 84) -* debugger commands, up: Execution Stack. (line 34) +* debugger commands, up: Execution Stack. (line 36) * debugger commands, w (watch): Viewing And Changing Data. (line 67) * debugger commands, watch: Viewing And Changing Data. (line 67) +* debugger commands, where (backtrace): Execution Stack. (line 13) * debugger default list amount: Debugger Info. (line 69) * debugger history file: Debugger Info. (line 80) * debugger history size: Debugger Info. (line 65) @@ -32043,10 +32370,10 @@ Index * debugger, read commands from a file: Debugger Info. (line 96) * debugging awk programs: Debugger. (line 6) * debugging gawk, bug reports: Bugs. (line 9) -* decimal point character, locale specific: Options. (line 268) +* decimal point character, locale specific: Options. (line 270) * decrement operators: Increment Ops. (line 35) * default keyword: Switch Statement. (line 6) -* Deifik, Scott <1>: Bugs. (line 71) +* Deifik, Scott <1>: Bugs. (line 72) * Deifik, Scott <2>: Contributors. (line 53) * Deifik, Scott: Acknowledgments. (line 60) * delete ARRAY: Delete. (line 39) @@ -32060,7 +32387,7 @@ Index * deleting entire arrays: Delete. (line 39) * Demaille, Akim: Acknowledgments. (line 60) * describe call stack frame, in debugger: Debugger Info. (line 27) -* differences between gawk and awk: String Functions. (line 197) +* differences between gawk and awk: String Functions. (line 200) * differences in awk and gawk, ARGC/ARGV variables: ARGC and ARGV. (line 90) * differences in awk and gawk, ARGIND variable: Auto-set. (line 44) @@ -32083,7 +32410,7 @@ Index * differences in awk and gawk, command-line directories: Command-line directories. (line 6) * differences in awk and gawk, ERRNO variable: Auto-set. (line 82) -* differences in awk and gawk, error messages: Special FD. (line 16) +* differences in awk and gawk, error messages: Special FD. (line 19) * differences in awk and gawk, FIELDWIDTHS variable: User-modified. (line 37) * differences in awk and gawk, FPAT variable: User-modified. (line 43) @@ -32094,26 +32421,26 @@ Index * differences in awk and gawk, IGNORECASE variable: User-modified. (line 76) * differences in awk and gawk, implementation limitations <1>: Redirection. - (line 135) + (line 129) * differences in awk and gawk, implementation limitations: Getline Notes. (line 14) * differences in awk and gawk, indirect function calls: Indirect Calls. (line 6) * differences in awk and gawk, input/output operators <1>: Redirection. - (line 102) + (line 96) * differences in awk and gawk, input/output operators: Getline/Coprocess. (line 6) * differences in awk and gawk, line continuations: Conditional Exp. (line 34) * differences in awk and gawk, LINT variable: User-modified. (line 88) * differences in awk and gawk, match() function: String Functions. - (line 260) + (line 262) * differences in awk and gawk, print/printf statements: Format Modifiers. (line 13) * differences in awk and gawk, PROCINFO array: Auto-set. (line 137) * differences in awk and gawk, read timeouts: Read Timeout. (line 6) * differences in awk and gawk, record separators: awk split records. - (line 124) + (line 125) * differences in awk and gawk, regexp constants: Using Constant Regexps. (line 43) * differences in awk and gawk, regular expressions: Case-sensitivity. @@ -32124,13 +32451,13 @@ Index * differences in awk and gawk, single-character fields: Single Character Fields. (line 6) * differences in awk and gawk, split() function: String Functions. - (line 347) + (line 348) * differences in awk and gawk, strings: Scalar Constants. (line 20) * differences in awk and gawk, strings, storing: gawk split records. (line 77) * differences in awk and gawk, SYMTAB variable: Auto-set. (line 276) * differences in awk and gawk, TEXTDOMAIN variable: User-modified. - (line 152) + (line 151) * differences in awk and gawk, trunc-mod operation: Arithmetic Ops. (line 66) * directories, command-line: Command-line directories. @@ -32158,13 +32485,14 @@ Index * dollar sign ($), regexp operator: Regexp Operators. (line 35) * double quote ("), in regexp constants: Computed Regexps. (line 29) * double quote ("), in shell commands: Quoting. (line 54) -* down debugger command: Execution Stack. (line 21) +* down debugger command: Execution Stack. (line 23) * Drepper, Ulrich: Acknowledgments. (line 52) +* Duman, Patrice: Acknowledgments. (line 74) * dump all variables of a program: Options. (line 93) * dump debugger command: Miscellaneous Debugger Commands. (line 9) * dupword.awk program: Dupword Program. (line 31) -* dynamic profiling: Profiling. (line 179) +* dynamic profiling: Profiling. (line 178) * dynamically loaded extensions: Dynamic Extensions. (line 6) * e debugger command (alias for enable): Breakpoint Control. (line 73) * EBCDIC: Ordinal Functions. (line 45) @@ -32185,7 +32513,7 @@ Index * empty array elements: Reference to Elements. (line 18) * empty pattern: Empty. (line 6) -* empty strings: awk split records. (line 114) +* empty strings: awk split records. (line 115) * empty strings, See null strings: Regexp Field Splitting. (line 43) * enable breakpoint: Breakpoint Control. (line 73) @@ -32202,16 +32530,16 @@ Index * END pattern, next/nextfile statements and <1>: Next Statement. (line 44) * END pattern, next/nextfile statements and: I/O And BEGIN/END. - (line 36) + (line 37) * END pattern, operators and: Using BEGIN/END. (line 17) * END pattern, print statement and: I/O And BEGIN/END. (line 16) * ENDFILE pattern: BEGINFILE/ENDFILE. (line 6) * ENDFILE pattern, Boolean patterns and: Expression Patterns. (line 70) -* endfile() user-defined function: Filetrans Function. (line 62) -* endgrent() function (C library): Group Functions. (line 212) -* endgrent() user-defined function: Group Functions. (line 215) -* endpwent() function (C library): Passwd Functions. (line 210) -* endpwent() user-defined function: Passwd Functions. (line 213) +* endfile() user-defined function: Filetrans Function. (line 61) +* endgrent() function (C library): Group Functions. (line 211) +* endgrent() user-defined function: Group Functions. (line 214) +* endpwent() function (C library): Passwd Functions. (line 207) +* endpwent() user-defined function: Passwd Functions. (line 210) * English, Steve: Advanced Features. (line 6) * ENVIRON array: Auto-set. (line 60) * environment variables used by gawk: Environment Variables. @@ -32227,9 +32555,9 @@ Index * ERRNO variable: Auto-set. (line 82) * ERRNO variable, with BEGINFILE pattern: BEGINFILE/ENDFILE. (line 26) * ERRNO variable, with close() function: Close Files And Pipes. - (line 139) + (line 140) * ERRNO variable, with getline command: Getline. (line 19) -* error handling: Special FD. (line 16) +* error handling: Special FD. (line 19) * error handling, ERRNO variable and: Auto-set. (line 82) * error output: Special FD. (line 6) * escape processing, gsub()/gensub()/sub() functions: Gory Details. @@ -32245,7 +32573,7 @@ Index * examining fields: Fields. (line 6) * exclamation point (!), ! operator <1>: Egrep Program. (line 175) * exclamation point (!), ! operator <2>: Precedence. (line 52) -* exclamation point (!), ! operator: Boolean Ops. (line 67) +* exclamation point (!), ! operator: Boolean Ops. (line 69) * exclamation point (!), != operator <1>: Precedence. (line 65) * exclamation point (!), != operator: Comparison Operators. (line 11) @@ -32265,7 +32593,7 @@ Index (line 99) * exp: Numeric Functions. (line 33) * expand utility: Very Simple. (line 72) -* Expat XML parser library: gawkextlib. (line 35) +* Expat XML parser library: gawkextlib. (line 31) * exponent: Numeric Functions. (line 33) * expressions: Expressions. (line 6) * expressions, as patterns: Expression Patterns. (line 6) @@ -32296,16 +32624,16 @@ Index * extensions, Brian Kernighan's awk: BTL. (line 6) * extensions, common, ** operator: Arithmetic Ops. (line 30) * extensions, common, **= operator: Assignment Ops. (line 137) -* extensions, common, /dev/stderr special file: Special FD. (line 46) -* extensions, common, /dev/stdin special file: Special FD. (line 46) -* extensions, common, /dev/stdout special file: Special FD. (line 46) +* extensions, common, /dev/stderr special file: Special FD. (line 48) +* extensions, common, /dev/stdin special file: Special FD. (line 48) +* extensions, common, /dev/stdout special file: Special FD. (line 48) * extensions, common, \x escape sequence: Escape Sequences. (line 61) * extensions, common, BINMODE variable: PC Using. (line 33) * extensions, common, delete to delete entire arrays: Delete. (line 39) * extensions, common, fflush() function: I/O Functions. (line 43) * extensions, common, func keyword: Definition Syntax. (line 93) * extensions, common, length() applied to an array: String Functions. - (line 197) + (line 200) * extensions, common, RS as a regexp: gawk split records. (line 6) * extensions, common, single character fields: Single Character Fields. (line 6) @@ -32317,7 +32645,7 @@ Index * extract.awk program: Extract Program. (line 79) * extraction, of marked strings (internationalization): String Extraction. (line 6) -* f debugger command (alias for frame): Execution Stack. (line 25) +* f debugger command (alias for frame): Execution Stack. (line 27) * false, logical: Truth Values. (line 6) * FDL (Free Documentation License): GNU Free Documentation License. (line 7) @@ -32345,7 +32673,7 @@ Index (line 6) * field separators, regular expressions as: Field Separators. (line 51) * field separators, See Also OFS: Changing Fields. (line 64) -* field separators, spaces as: Cut Program. (line 108) +* field separators, spaces as: Cut Program. (line 103) * fields <1>: Basic High Level. (line 73) * fields <2>: Fields. (line 6) * fields: Reading Files. (line 14) @@ -32365,7 +32693,7 @@ Index * file inclusion, @include directive: Include Files. (line 8) * file names, distinguishing: Auto-set. (line 56) * file names, in compatibility mode: Special Caveats. (line 9) -* file names, standard streams in gawk: Special FD. (line 46) +* file names, standard streams in gawk: Special FD. (line 48) * FILENAME variable <1>: Auto-set. (line 98) * FILENAME variable: Reading Files. (line 6) * FILENAME variable, getline, setting with: Getline Notes. (line 19) @@ -32373,12 +32701,12 @@ Index * files, .gmo: Explaining gettext. (line 42) * files, .gmo, specifying directory of <1>: Programmer i18n. (line 47) * files, .gmo, specifying directory of: Explaining gettext. (line 54) -* files, .mo, converting from .po: I18N Example. (line 63) +* files, .mo, converting from .po: I18N Example. (line 64) * files, .po <1>: Translator i18n. (line 6) * files, .po: Explaining gettext. (line 37) -* files, .po, converting to .mo: I18N Example. (line 63) +* files, .po, converting to .mo: I18N Example. (line 64) * files, .pot: Explaining gettext. (line 31) -* files, /dev/... special files: Special FD. (line 46) +* files, /dev/... special files: Special FD. (line 48) * files, /inet/... (gawk): TCP/IP Networking. (line 6) * files, /inet4/... (gawk): TCP/IP Networking. (line 6) * files, /inet6/... (gawk): TCP/IP Networking. (line 6) @@ -32396,12 +32724,12 @@ Index * files, managing, data file boundaries: Filetrans Function. (line 6) * files, message object: Explaining gettext. (line 42) * files, message object, converting from portable object files: I18N Example. - (line 63) + (line 64) * files, message object, specifying directory of <1>: Programmer i18n. (line 47) * files, message object, specifying directory of: Explaining gettext. (line 54) -* files, multiple passes over: Other Arguments. (line 53) +* files, multiple passes over: Other Arguments. (line 56) * files, multiple, duplicating output into: Tee Program. (line 6) * files, output, See output files: Close Files And Pipes. (line 6) @@ -32410,7 +32738,7 @@ Index * files, portable object: Explaining gettext. (line 37) * files, portable object template: Explaining gettext. (line 31) * files, portable object, converting to message object files: I18N Example. - (line 63) + (line 64) * files, portable object, generating: Options. (line 147) * files, processing, ARGIND variable and: Auto-set. (line 51) * files, reading: Rewind Function. (line 6) @@ -32427,7 +32755,7 @@ Index * Fish, Fred: Contributors. (line 50) * fixed-width data: Constant Size. (line 10) * flag variables <1>: Tee Program. (line 20) -* flag variables: Boolean Ops. (line 67) +* flag variables: Boolean Ops. (line 69) * floating-point, numbers, arbitrary precision: Arbitrary Precision Arithmetic. (line 6) * floating-point, VAX/VMS: VMS Running. (line 51) @@ -32436,7 +32764,7 @@ Index (line 12) * FNR variable <1>: Auto-set. (line 107) * FNR variable: Records. (line 6) -* FNR variable, changing: Auto-set. (line 316) +* FNR variable, changing: Auto-set. (line 321) * for statement: For Statement. (line 6) * for statement, looping over arrays: Scanning an Array. (line 20) * fork() extension function: Extension Sample Fork. @@ -32450,7 +32778,7 @@ Index * format time string: Time Functions. (line 48) * formats, numeric output: OFMT. (line 6) * formatting output: Printf. (line 6) -* formatting strings: String Functions. (line 381) +* formatting strings: String Functions. (line 382) * forward slash (/) to enclose regular expressions: Regexp. (line 10) * forward slash (/), / operator: Precedence. (line 55) * forward slash (/), /= operator <1>: Precedence. (line 95) @@ -32461,7 +32789,7 @@ Index * FPAT variable <1>: User-modified. (line 43) * FPAT variable: Splitting By Content. (line 27) -* frame debugger command: Execution Stack. (line 25) +* frame debugger command: Execution Stack. (line 27) * Free Documentation License (FDL): GNU Free Documentation License. (line 7) * Free Software Foundation (FSF) <1>: Glossary. (line 296) @@ -32473,9 +32801,9 @@ Index * FS variable, --field-separator option and: Options. (line 21) * FS variable, as null string: Single Character Fields. (line 20) -* FS variable, as TAB character: Options. (line 264) +* FS variable, as TAB character: Options. (line 266) * FS variable, changing value of: Field Separators. (line 35) -* FS variable, running awk programs and: Cut Program. (line 68) +* FS variable, running awk programs and: Cut Program. (line 63) * FS variable, setting from command line: Command Line Field Separator. (line 6) * FS, containing ^: Regexp Field Splitting. @@ -32500,7 +32828,7 @@ Index * functions, defining: Definition Syntax. (line 9) * functions, library: Library Functions. (line 6) * functions, library, assertions: Assert Function. (line 6) -* functions, library, associative arrays and: Library Names. (line 57) +* functions, library, associative arrays and: Library Names. (line 58) * functions, library, C library: Getopt Function. (line 6) * functions, library, character values as numbers: Ordinal Functions. (line 6) @@ -32520,8 +32848,7 @@ Index * functions, library, rounding numbers: Round Function. (line 6) * functions, library, user database, reading: Passwd Functions. (line 6) -* functions, names of <1>: Definition Syntax. (line 23) -* functions, names of: Arrays. (line 18) +* functions, names of: Definition Syntax. (line 23) * functions, recursive: Definition Syntax. (line 83) * functions, string-translation: I18N Functions. (line 6) * functions, undefined: Pass By Value/Reference. @@ -32534,22 +32861,19 @@ Index (line 47) * functions, user-defined, next/nextfile statements and: Next Statement. (line 44) -* G-d: Acknowledgments. (line 92) +* G-d: Acknowledgments. (line 94) * Garfinkle, Scott: Contributors. (line 34) -* gawk program, dynamic profiling: Profiling. (line 179) +* gawk program, dynamic profiling: Profiling. (line 178) * gawk version: Auto-set. (line 214) -* gawk, ARGIND variable in: Other Arguments. (line 12) +* gawk, ARGIND variable in: Other Arguments. (line 15) * gawk, awk and <1>: This Manual. (line 14) * gawk, awk and: Preface. (line 21) -* gawk, bitwise operations in: Bitwise Functions. (line 39) +* gawk, bitwise operations in: Bitwise Functions. (line 40) * gawk, break statement in: Break Statement. (line 51) -* gawk, built-in variables and: Built-in Variables. (line 14) * gawk, character classes and: Bracket Expressions. (line 100) * gawk, coding style in: Adding Code. (line 39) * gawk, command-line options, and regular expressions: GNU Regexp Operators. (line 70) -* gawk, comparison operators and: Comparison Operators. - (line 50) * gawk, configuring: Configuration Philosophy. (line 6) * gawk, configuring, options: Additional Configuration Options. @@ -32561,10 +32885,10 @@ Index * gawk, ERRNO variable in <2>: Auto-set. (line 82) * gawk, ERRNO variable in <3>: BEGINFILE/ENDFILE. (line 26) * gawk, ERRNO variable in <4>: Close Files And Pipes. - (line 139) + (line 140) * gawk, ERRNO variable in: Getline. (line 19) -* gawk, escape sequences: Escape Sequences. (line 132) -* gawk, extensions, disabling: Options. (line 252) +* gawk, escape sequences: Escape Sequences. (line 133) +* gawk, extensions, disabling: Options. (line 254) * gawk, features, adding: Adding Code. (line 6) * gawk, features, advanced: Advanced Features. (line 6) * gawk, field separators and: User-modified. (line 71) @@ -32580,7 +32904,7 @@ Index * gawk, hexadecimal numbers and: Nondecimal-numbers. (line 42) * gawk, IGNORECASE variable in <1>: Array Sorting Functions. (line 83) -* gawk, IGNORECASE variable in <2>: String Functions. (line 58) +* gawk, IGNORECASE variable in <2>: String Functions. (line 57) * gawk, IGNORECASE variable in <3>: Array Intro. (line 94) * gawk, IGNORECASE variable in <4>: User-modified. (line 76) * gawk, IGNORECASE variable in: Case-sensitivity. (line 26) @@ -32589,7 +32913,7 @@ Index * gawk, implementation issues, downward compatibility: Compatibility Mode. (line 6) * gawk, implementation issues, limits: Getline Notes. (line 14) -* gawk, implementation issues, pipes: Redirection. (line 135) +* gawk, implementation issues, pipes: Redirection. (line 129) * gawk, installing: Installation. (line 6) * gawk, internationalization and, See internationalization: Internationalization. (line 13) @@ -32604,6 +32928,7 @@ Index * gawk, newlines in: Statements/Lines. (line 12) * gawk, octal numbers and: Nondecimal-numbers. (line 42) * gawk, OS/2 version of: PC Using. (line 16) +* gawk, predefined variables and: Built-in Variables. (line 14) * gawk, PROCINFO array in <1>: Two-way I/O. (line 99) * gawk, PROCINFO array in <2>: Time Functions. (line 47) * gawk, PROCINFO array in: Auto-set. (line 137) @@ -32616,21 +32941,27 @@ Index * gawk, regular expressions, precedence: Regexp Operators. (line 161) * gawk, RT variable in <1>: Auto-set. (line 272) * gawk, RT variable in <2>: Multiple Line. (line 129) -* gawk, RT variable in: awk split records. (line 124) +* gawk, RT variable in: awk split records. (line 125) * gawk, See Also awk: Preface. (line 34) * gawk, source code, obtaining: Getting. (line 6) * gawk, splitting fields and: Constant Size. (line 88) * gawk, string-translation functions: I18N Functions. (line 6) * gawk, SYMTAB array in: Auto-set. (line 276) -* gawk, TEXTDOMAIN variable in: User-modified. (line 152) +* gawk, TEXTDOMAIN variable in: User-modified. (line 151) * gawk, timestamps: Time Functions. (line 6) * gawk, uses for: Preface. (line 34) -* gawk, versions of, information about, printing: Options. (line 298) +* gawk, versions of, information about, printing: Options. (line 300) * gawk, VMS version of: VMS Installation. (line 6) * gawk, word-boundary operator: GNU Regexp Operators. (line 63) * gawkextlib: gawkextlib. (line 6) * gawkextlib project: gawkextlib. (line 6) +* gawklibpath_append shell function: Shell Startup Files. (line 29) +* gawklibpath_default shell function: Shell Startup Files. (line 22) +* gawklibpath_prepend shell function: Shell Startup Files. (line 25) +* gawkpath_append shell function: Shell Startup Files. (line 19) +* gawkpath_default shell function: Shell Startup Files. (line 12) +* gawkpath_prepend shell function: Shell Startup Files. (line 15) * General Public License (GPL): Glossary. (line 305) * General Public License, See GPL: Manual History. (line 11) * generate time values: Time Functions. (line 25) @@ -32641,12 +32972,12 @@ Index * getaddrinfo() function (C library): TCP/IP Networking. (line 38) * getgrent() function (C library): Group Functions. (line 6) * getgrent() user-defined function: Group Functions. (line 6) -* getgrgid() function (C library): Group Functions. (line 183) -* getgrgid() user-defined function: Group Functions. (line 186) -* getgrnam() function (C library): Group Functions. (line 172) -* getgrnam() user-defined function: Group Functions. (line 177) -* getgruser() function (C library): Group Functions. (line 192) -* getgruser() function, user-defined: Group Functions. (line 195) +* getgrgid() function (C library): Group Functions. (line 182) +* getgrgid() user-defined function: Group Functions. (line 185) +* getgrnam() function (C library): Group Functions. (line 171) +* getgrnam() user-defined function: Group Functions. (line 176) +* getgruser() function (C library): Group Functions. (line 191) +* getgruser() function, user-defined: Group Functions. (line 194) * getline command: Reading Files. (line 20) * getline command, _gr_init() user-defined function: Group Functions. (line 83) @@ -32670,10 +33001,10 @@ Index * getopt() user-defined function: Getopt Function. (line 108) * getpwent() function (C library): Passwd Functions. (line 16) * getpwent() user-defined function: Passwd Functions. (line 16) -* getpwnam() function (C library): Passwd Functions. (line 177) -* getpwnam() user-defined function: Passwd Functions. (line 182) -* getpwuid() function (C library): Passwd Functions. (line 188) -* getpwuid() user-defined function: Passwd Functions. (line 192) +* getpwnam() function (C library): Passwd Functions. (line 174) +* getpwnam() user-defined function: Passwd Functions. (line 179) +* getpwuid() function (C library): Passwd Functions. (line 185) +* getpwuid() user-defined function: Passwd Functions. (line 189) * gettext library: Explaining gettext. (line 6) * gettext library, locale categories: Explaining gettext. (line 81) * gettext() function (C library): Explaining gettext. (line 63) @@ -32683,7 +33014,7 @@ Index * git utility <2>: Accessing The Source. (line 10) * git utility <3>: Other Versions. (line 29) -* git utility: gawkextlib. (line 29) +* git utility: gawkextlib. (line 25) * Git, use of for gawk source code: Derived Files. (line 6) * GNITS mailing list: Acknowledgments. (line 52) * GNU awk, See gawk: Preface. (line 51) @@ -32712,7 +33043,7 @@ Index * gsub <1>: String Functions. (line 139) * gsub: Using Constant Regexps. (line 43) -* gsub() function, arguments of: String Functions. (line 460) +* gsub() function, arguments of: String Functions. (line 461) * gsub() function, escape processing: Gory Details. (line 6) * h debugger command (alias for help): Miscellaneous Debugger Commands. (line 66) @@ -32729,7 +33060,7 @@ Index * history expansion, in debugger: Readline Support. (line 6) * histsort.awk program: History Sorting. (line 25) * Hughes, Phil: Acknowledgments. (line 43) -* HUP signal, for dynamic profiling: Profiling. (line 211) +* HUP signal, for dynamic profiling: Profiling. (line 210) * hyphen (-), - operator: Precedence. (line 52) * hyphen (-), -- operator <1>: Precedence. (line 46) * hyphen (-), -- operator: Increment Ops. (line 48) @@ -32758,9 +33089,9 @@ Index * Illumos, POSIX-compliant awk: Other Versions. (line 105) * implementation issues, gawk: Notes. (line 6) * implementation issues, gawk, debugging: Compatibility Mode. (line 6) -* implementation issues, gawk, limits <1>: Redirection. (line 135) +* implementation issues, gawk, limits <1>: Redirection. (line 129) * implementation issues, gawk, limits: Getline Notes. (line 14) -* in operator <1>: For Statement. (line 75) +* in operator <1>: For Statement. (line 76) * in operator <2>: Precedence. (line 83) * in operator: Comparison Operators. (line 11) @@ -32789,9 +33120,9 @@ Index * input files, examples: Sample Data Files. (line 6) * input files, reading: Reading Files. (line 6) * input files, running awk without: Read Terminal. (line 6) -* input files, variable assignments and: Other Arguments. (line 23) +* input files, variable assignments and: Other Arguments. (line 26) * input pipeline: Getline/Pipe. (line 9) -* input record, length of: String Functions. (line 174) +* input record, length of: String Functions. (line 177) * input redirection: Getline/File. (line 6) * input, data, nondecimal: Nondecimal Data. (line 6) * input, explicit: Getline. (line 6) @@ -32809,18 +33140,18 @@ Index * installing gawk: Installation. (line 6) * instruction tracing, in debugger: Debugger Info. (line 89) * int: Numeric Functions. (line 38) -* INT signal (MS-Windows): Profiling. (line 214) +* INT signal (MS-Windows): Profiling. (line 213) * integer array indices: Numeric Array Subscripts. (line 31) * integers, arbitrary precision: Arbitrary Precision Integers. (line 6) * integers, unsigned: Computer Arithmetic. (line 41) -* interacting with other programs: I/O Functions. (line 75) +* interacting with other programs: I/O Functions. (line 74) * internationalization <1>: I18N and L10N. (line 6) * internationalization: I18N Functions. (line 6) * internationalization, localization <1>: Internationalization. (line 13) -* internationalization, localization: User-modified. (line 152) +* internationalization, localization: User-modified. (line 151) * internationalization, localization, character classes: Bracket Expressions. (line 100) * internationalization, localization, gawk and: Internationalization. @@ -32836,7 +33167,7 @@ Index * interpreted programs: Basic High Level. (line 15) * interval expressions, regexp operator: Regexp Operators. (line 116) * inventory-shipped file: Sample Data Files. (line 32) -* invoke shell command: I/O Functions. (line 75) +* invoke shell command: I/O Functions. (line 74) * isarray: Type Functions. (line 11) * ISO: Glossary. (line 367) * ISO 8859-1: Glossary. (line 133) @@ -32862,10 +33193,10 @@ Index * Kernighan, Brian <6>: Library Functions. (line 12) * Kernighan, Brian <7>: Concatenation. (line 6) * Kernighan, Brian <8>: Getline/Pipe. (line 6) -* Kernighan, Brian <9>: Acknowledgments. (line 76) +* Kernighan, Brian <9>: Acknowledgments. (line 78) * Kernighan, Brian <10>: Conventions. (line 38) * Kernighan, Brian: History. (line 17) -* kill command, dynamic profiling: Profiling. (line 188) +* kill command, dynamic profiling: Profiling. (line 187) * Knights, jedi: Undocumented. (line 6) * Kwok, Conrad: Contributors. (line 34) * l debugger command (alias for list): Miscellaneous Debugger Commands. @@ -32878,7 +33209,7 @@ Index * LC_CTYPE locale category: Explaining gettext. (line 98) * LC_MESSAGES locale category: Explaining gettext. (line 88) * LC_MESSAGES locale category, bindtextdomain() function (gawk): Programmer i18n. - (line 99) + (line 101) * LC_MONETARY locale category: Explaining gettext. (line 104) * LC_NUMERIC locale category: Explaining gettext. (line 108) * LC_TIME locale category: Explaining gettext. (line 112) @@ -32889,19 +33220,19 @@ Index * left angle bracket (<), <= operator <1>: Precedence. (line 65) * left angle bracket (<), <= operator: Comparison Operators. (line 11) -* left shift: Bitwise Functions. (line 46) +* left shift: Bitwise Functions. (line 47) * left shift, bitwise: Bitwise Functions. (line 32) * leftmost longest match: Multiple Line. (line 26) -* length: String Functions. (line 167) -* length of input record: String Functions. (line 174) -* length of string: String Functions. (line 167) +* length: String Functions. (line 170) +* length of input record: String Functions. (line 177) +* length of string: String Functions. (line 170) * Lesser General Public License (LGPL): Glossary. (line 396) * LGPL (Lesser General Public License): Glossary. (line 396) * libmawk: Other Versions. (line 121) * libraries of awk functions: Library Functions. (line 6) * libraries of awk functions, assertions: Assert Function. (line 6) * libraries of awk functions, associative arrays and: Library Names. - (line 57) + (line 58) * libraries of awk functions, character values as numbers: Ordinal Functions. (line 6) * libraries of awk functions, command-line options: Getopt Function. @@ -32921,7 +33252,7 @@ Index * libraries of awk functions, user database, reading: Passwd Functions. (line 6) * line breaks: Statements/Lines. (line 6) -* line continuations: Boolean Ops. (line 62) +* line continuations: Boolean Ops. (line 64) * line continuations, gawk: Conditional Exp. (line 34) * line continuations, in print statement: Print Examples. (line 76) * line continuations, with C shell: More Complex. (line 30) @@ -32937,7 +33268,7 @@ Index * lint checking, empty programs: Command Line. (line 16) * lint checking, issuing warnings: Options. (line 185) * lint checking, POSIXLY_CORRECT environment variable: Options. - (line 336) + (line 339) * lint checking, undefined functions: Pass By Value/Reference. (line 88) * LINT variable: User-modified. (line 88) @@ -32953,7 +33284,7 @@ Index * loading, extensions: Options. (line 173) * local variables, in a function: Variable Scope. (line 6) * locale categories: Explaining gettext. (line 81) -* locale decimal point character: Options. (line 268) +* locale decimal point character: Options. (line 270) * locale, definition of: Locales. (line 6) * localization: I18N and L10N. (line 6) * localization, See internationalization, localization: I18N and L10N. @@ -32967,7 +33298,7 @@ Index * long options: Command Line. (line 13) * loops: While Statement. (line 6) * loops, break statement and: Break Statement. (line 6) -* loops, continue statements and: For Statement. (line 64) +* loops, continue statements and: For Statement. (line 65) * loops, count for header, in a profile: Profiling. (line 131) * loops, do-while: Do Statement. (line 6) * loops, exiting: Break Statement. (line 6) @@ -32976,67 +33307,66 @@ Index * loops, See Also while statement: While Statement. (line 6) * loops, while: While Statement. (line 6) * ls utility: More Complex. (line 15) -* lshift: Bitwise Functions. (line 46) +* lshift: Bitwise Functions. (line 47) * lvalues/rvalues: Assignment Ops. (line 32) * mail-list file: Sample Data Files. (line 6) * mailing labels, printing: Labels Program. (line 6) * mailing list, GNITS: Acknowledgments. (line 52) -* Malmberg, John <1>: Bugs. (line 71) +* Malmberg, John <1>: Bugs. (line 72) * Malmberg, John: Acknowledgments. (line 60) +* Malmberg, John E.: Contributors. (line 137) * mark parity: Ordinal Functions. (line 45) * marked string extraction (internationalization): String Extraction. (line 6) * marked strings, extracting: String Extraction. (line 6) * Marx, Groucho: Increment Ops. (line 60) -* match: String Functions. (line 207) -* match regexp in string: String Functions. (line 207) +* match: String Functions. (line 210) +* match regexp in string: String Functions. (line 210) * match() function, RSTART/RLENGTH variables: String Functions. - (line 224) + (line 227) * matching, expressions, See comparison expressions: Typing and Comparison. (line 9) * matching, leftmost longest: Multiple Line. (line 26) -* matching, null strings: Gory Details. (line 143) +* matching, null strings: String Functions. (line 535) * mawk utility <1>: Other Versions. (line 44) * mawk utility <2>: Nextfile Statement. (line 47) * mawk utility <3>: Concatenation. (line 36) * mawk utility <4>: Getline/Pipe. (line 62) -* mawk utility: Escape Sequences. (line 132) +* mawk utility: Escape Sequences. (line 133) * maximum precision supported by MPFR library: Auto-set. (line 228) * McIlroy, Doug: Glossary. (line 149) * McPhee, Patrick: Contributors. (line 100) * message object files: Explaining gettext. (line 42) * message object files, converting from portable object files: I18N Example. - (line 63) + (line 64) * message object files, specifying directory of <1>: Programmer i18n. (line 47) * message object files, specifying directory of: Explaining gettext. (line 54) * messages from extensions: Printing Messages. (line 6) * metacharacters in regular expressions: Regexp Operators. (line 6) -* metacharacters, escape sequences for: Escape Sequences. (line 138) +* metacharacters, escape sequences for: Escape Sequences. (line 139) * minimum precision supported by MPFR library: Auto-set. (line 231) * mktime: Time Functions. (line 25) * modifiers, in format specifiers: Format Modifiers. (line 6) * monetary information, localization: Explaining gettext. (line 104) * Moore, Duncan: Getline Notes. (line 40) -* msgfmt utility: I18N Example. (line 63) +* msgfmt utility: I18N Example. (line 64) * multiple precision: Arbitrary Precision Arithmetic. (line 6) * multiple-line records: Multiple Line. (line 6) * n debugger command (alias for next): Debugger Execution Control. (line 43) -* names, arrays/variables <1>: Library Names. (line 6) -* names, arrays/variables: Arrays. (line 18) +* names, arrays/variables: Library Names. (line 6) * names, functions <1>: Library Names. (line 6) * names, functions: Definition Syntax. (line 23) -* namespace issues <1>: Library Names. (line 6) -* namespace issues: Arrays. (line 18) +* namespace issues: Library Names. (line 6) * namespace issues, functions: Definition Syntax. (line 23) * NetBSD: Glossary. (line 611) * networks, programming: TCP/IP Networking. (line 6) * networks, support for: Special Network. (line 6) -* newlines <1>: Boolean Ops. (line 67) -* newlines <2>: Options. (line 258) +* newlines <1>: Boolean Ops. (line 69) +* newlines <2>: Options. (line 260) * newlines: Statements/Lines. (line 6) * newlines, as field separators: Default Field Splitting. (line 6) @@ -33051,14 +33381,14 @@ Index (line 43) * next file statement: Feature History. (line 169) * next statement <1>: Next Statement. (line 6) -* next statement: Boolean Ops. (line 93) -* next statement, BEGIN/END patterns and: I/O And BEGIN/END. (line 36) +* next statement: Boolean Ops. (line 95) +* next statement, BEGIN/END patterns and: I/O And BEGIN/END. (line 37) * next statement, BEGINFILE/ENDFILE patterns and: BEGINFILE/ENDFILE. (line 49) * next statement, user-defined functions and: Next Statement. (line 44) * nextfile statement: Nextfile Statement. (line 6) * nextfile statement, BEGIN/END patterns and: I/O And BEGIN/END. - (line 36) + (line 37) * nextfile statement, BEGINFILE/ENDFILE patterns and: BEGINFILE/ENDFILE. (line 26) * nextfile statement, user-defined functions and: Nextfile Statement. @@ -33076,21 +33406,21 @@ Index * not Boolean-logic operator: Boolean Ops. (line 6) * NR variable <1>: Auto-set. (line 132) * NR variable: Records. (line 6) -* NR variable, changing: Auto-set. (line 316) +* NR variable, changing: Auto-set. (line 321) * null strings <1>: Basic Data Typing. (line 26) * null strings <2>: Truth Values. (line 6) * null strings <3>: Regexp Field Splitting. (line 43) -* null strings: awk split records. (line 114) -* null strings in gawk arguments, quoting and: Quoting. (line 79) +* null strings: awk split records. (line 115) +* null strings in gawk arguments, quoting and: Quoting. (line 82) * null strings, and deleting array elements: Delete. (line 27) * null strings, as array subscripts: Uninitialized Subscripts. (line 43) * null strings, converting numbers to strings: Strings And Numbers. (line 21) -* null strings, matching: Gory Details. (line 143) -* number as string of bits: Bitwise Functions. (line 109) -* number of array elements: String Functions. (line 197) +* null strings, matching: String Functions. (line 535) +* number as string of bits: Bitwise Functions. (line 110) +* number of array elements: String Functions. (line 200) * number sign (#), #! (executable scripts): Executable Scripts. (line 6) * number sign (#), commenting: Comments. (line 6) @@ -33099,7 +33429,7 @@ Index * numbers, as values of characters: Ordinal Functions. (line 6) * numbers, Cliff random: Cliff Random Function. (line 6) -* numbers, converting <1>: Bitwise Functions. (line 109) +* numbers, converting <1>: Bitwise Functions. (line 110) * numbers, converting: Strings And Numbers. (line 6) * numbers, converting, to strings: User-modified. (line 30) * numbers, hexadecimal: Nondecimal-numbers. (line 6) @@ -33117,7 +33447,7 @@ Index * OFMT variable <2>: Strings And Numbers. (line 57) * OFMT variable: OFMT. (line 15) * OFMT variable, POSIX awk and: OFMT. (line 27) -* OFS variable <1>: User-modified. (line 114) +* OFS variable <1>: User-modified. (line 113) * OFS variable <2>: Output Separators. (line 6) * OFS variable: Changing Fields. (line 64) * OpenBSD: Glossary. (line 611) @@ -33147,7 +33477,7 @@ Index * operators, precedence: Increment Ops. (line 60) * operators, relational, See operators, comparison: Typing and Comparison. (line 9) -* operators, short-circuit: Boolean Ops. (line 57) +* operators, short-circuit: Boolean Ops. (line 59) * operators, string: Concatenation. (line 8) * operators, string-matching: Regexp Usage. (line 19) * operators, string-matching, for buffers: GNU Regexp Operators. @@ -33163,14 +33493,14 @@ Index * options, long <1>: Options. (line 6) * options, long: Command Line. (line 13) * options, printing list of: Options. (line 154) -* or: Bitwise Functions. (line 49) +* or: Bitwise Functions. (line 50) * OR bitwise operation: Bitwise Functions. (line 6) * or Boolean-logic operator: Boolean Ops. (line 6) * ord() extension function: Extension Sample Ord. (line 12) * ord() user-defined function: Ordinal Functions. (line 16) * order of evaluation, concatenation: Concatenation. (line 41) -* ORS variable <1>: User-modified. (line 119) +* ORS variable <1>: User-modified. (line 118) * ORS variable: Output Separators. (line 20) * output field separator, See OFS variable: Changing Fields. (line 64) * output record separator, See ORS variable: Output Separators. @@ -33194,7 +33524,7 @@ Index * parentheses (), in a profile: Profiling. (line 146) * parentheses (), regexp operator: Regexp Operators. (line 81) * password file: Passwd Functions. (line 16) -* patsplit: String Functions. (line 294) +* patsplit: String Functions. (line 296) * patterns: Patterns and Actions. (line 6) * patterns, comparison expressions as: Expression Patterns. (line 14) @@ -33221,7 +33551,7 @@ Index (line 6) * pipe, input: Getline/Pipe. (line 9) * pipe, output: Redirection. (line 57) -* Pitts, Dave <1>: Bugs. (line 71) +* Pitts, Dave <1>: Bugs. (line 72) * Pitts, Dave: Acknowledgments. (line 60) * Plauger, P.J.: Library Functions. (line 12) * plug-in: Extension Intro. (line 6) @@ -33232,14 +33562,14 @@ Index * plus sign (+), += operator: Assignment Ops. (line 82) * plus sign (+), regexp operator: Regexp Operators. (line 105) * pointers to functions: Indirect Calls. (line 6) -* portability: Escape Sequences. (line 102) +* portability: Escape Sequences. (line 103) * portability, #! (executable scripts): Executable Scripts. (line 33) * portability, ** operator and: Arithmetic Ops. (line 81) * portability, **= operator and: Assignment Ops. (line 143) * portability, ARGV variable: Executable Scripts. (line 59) * portability, backslash continuation and: Statements/Lines. (line 30) * portability, backslash in escape sequences: Escape Sequences. - (line 120) + (line 121) * portability, close() function and: Close Files And Pipes. (line 81) * portability, data files as single record: gawk split records. @@ -33250,19 +33580,19 @@ Index * portability, gawk: New Ports. (line 6) * portability, gettext library and: Explaining gettext. (line 11) * portability, internationalization and: I18N Portability. (line 6) -* portability, length() function: String Functions. (line 176) +* portability, length() function: String Functions. (line 179) * portability, new awk vs. old awk: Strings And Numbers. (line 57) * portability, next statement in user-defined functions: Pass By Value/Reference. (line 91) * portability, NF variable, decrementing: Changing Fields. (line 115) * portability, operators: Increment Ops. (line 60) * portability, operators, not in POSIX awk: Precedence. (line 98) -* portability, POSIXLY_CORRECT environment variable: Options. (line 356) -* portability, substr() function: String Functions. (line 510) +* portability, POSIXLY_CORRECT environment variable: Options. (line 359) +* portability, substr() function: String Functions. (line 511) * portable object files <1>: Translator i18n. (line 6) * portable object files: Explaining gettext. (line 37) * portable object files, converting to message object files: I18N Example. - (line 63) + (line 64) * portable object files, generating: Options. (line 147) * portable object template files: Explaining gettext. (line 31) * porting gawk: New Ports. (line 6) @@ -33278,7 +33608,7 @@ Index * POSIX awk, < operator and: Getline/File. (line 26) * POSIX awk, arithmetic operators and: Arithmetic Ops. (line 30) * POSIX awk, backslashes in string constants: Escape Sequences. - (line 120) + (line 121) * POSIX awk, BEGIN/END patterns: I/O And BEGIN/END. (line 16) * POSIX awk, bracket expressions and: Bracket Expressions. (line 26) * POSIX awk, bracket expressions and, character classes: Bracket Expressions. @@ -33294,7 +33624,7 @@ Index * POSIX awk, FS variable and: User-modified. (line 60) * POSIX awk, function keyword in: Definition Syntax. (line 93) * POSIX awk, functions and, gsub()/sub(): Gory Details. (line 90) -* POSIX awk, functions and, length(): String Functions. (line 176) +* POSIX awk, functions and, length(): String Functions. (line 179) * POSIX awk, GNU long options and: Options. (line 15) * POSIX awk, interval expressions in: Regexp Operators. (line 135) * POSIX awk, next/nextfile statements and: Next Statement. (line 44) @@ -33302,19 +33632,23 @@ Index * POSIX awk, OFMT variable and <1>: Strings And Numbers. (line 57) * POSIX awk, OFMT variable and: OFMT. (line 27) * POSIX awk, period (.), using: Regexp Operators. (line 51) -* POSIX awk, printf format strings and: Format Modifiers. (line 159) +* POSIX awk, printf format strings and: Format Modifiers. (line 158) * POSIX awk, regular expressions and: Regexp Operators. (line 161) * POSIX awk, timestamps and: Time Functions. (line 6) * POSIX awk, | I/O operator and: Getline/Pipe. (line 55) -* POSIX mode: Options. (line 252) +* POSIX mode: Options. (line 254) * POSIX, awk and: Preface. (line 21) * POSIX, gawk extensions not included in: POSIX/GNU. (line 6) * POSIX, programs, implementing in awk: Clones. (line 6) -* POSIXLY_CORRECT environment variable: Options. (line 336) -* PREC variable: User-modified. (line 124) +* POSIXLY_CORRECT environment variable: Options. (line 339) +* PREC variable: User-modified. (line 123) * precedence <1>: Precedence. (line 6) * precedence: Increment Ops. (line 60) * precedence, regexp operators: Regexp Operators. (line 156) +* predefined variables: Built-in Variables. (line 6) +* predefined variables, -v option, setting with: Options. (line 40) +* predefined variables, conveying information: Auto-set. (line 6) +* predefined variables, user-modifiable: User-modified. (line 6) * print debugger command: Viewing And Changing Data. (line 36) * print statement: Printing. (line 16) @@ -33322,7 +33656,7 @@ Index * print statement, commas, omitting: Print Examples. (line 31) * print statement, I/O operators in: Precedence. (line 71) * print statement, line continuations and: Print Examples. (line 76) -* print statement, OFMT variable and: User-modified. (line 114) +* print statement, OFMT variable and: User-modified. (line 113) * print statement, See Also redirection, of output: Redirection. (line 17) * print statement, sprintf() function and: Round Function. (line 6) @@ -33364,16 +33698,16 @@ Index * PROCINFO array, and group membership: Group Functions. (line 6) * PROCINFO array, and user and group ID numbers: Id Program. (line 15) * PROCINFO array, testing the field splitting: Passwd Functions. - (line 161) + (line 154) * PROCINFO array, uses: Auto-set. (line 249) * PROCINFO, values of sorted_in: Controlling Scanning. (line 26) * profiling awk programs: Profiling. (line 6) -* profiling awk programs, dynamically: Profiling. (line 179) +* profiling awk programs, dynamically: Profiling. (line 178) * program identifiers: Auto-set. (line 155) * program, definition of: Getting Started. (line 21) * programming conventions, --non-decimal-data option: Nondecimal Data. - (line 36) + (line 35) * programming conventions, ARGC/ARGV variables: Auto-set. (line 35) * programming conventions, exit statement: Exit Statement. (line 38) * programming conventions, function parameters: Return Statement. @@ -33405,9 +33739,9 @@ Index * QuikTrim Awk: Other Versions. (line 135) * quit debugger command: Miscellaneous Debugger Commands. (line 99) -* QUIT signal (MS-Windows): Profiling. (line 214) +* QUIT signal (MS-Windows): Profiling. (line 213) * quoting in gawk command lines: Long. (line 26) -* quoting in gawk command lines, tricks for: Quoting. (line 88) +* quoting in gawk command lines, tricks for: Quoting. (line 91) * quoting, for small awk programs: Comments. (line 27) * r debugger command (alias for run): Debugger Execution Control. (line 62) @@ -33423,12 +33757,11 @@ Index * range expressions (regexps): Bracket Expressions. (line 6) * range patterns: Ranges. (line 6) * range patterns, line continuation and: Ranges. (line 65) -* Rankin, Pat <1>: Bugs. (line 71) -* Rankin, Pat <2>: Contributors. (line 37) -* Rankin, Pat <3>: Assignment Ops. (line 100) +* Rankin, Pat <1>: Contributors. (line 37) +* Rankin, Pat <2>: Assignment Ops. (line 100) * Rankin, Pat: Acknowledgments. (line 60) * reada() extension function: Extension Sample Read write array. - (line 15) + (line 18) * readable data files, checking: File Checking. (line 6) * readable.awk program: File Checking. (line 11) * readdir extension: Extension Sample Readdir. @@ -33438,19 +33771,19 @@ Index * readfile() user-defined function: Readfile Function. (line 30) * reading input files: Reading Files. (line 6) * recipe for a programming language: History. (line 6) -* record separators <1>: User-modified. (line 133) +* record separators <1>: User-modified. (line 132) * record separators: awk split records. (line 6) * record separators, changing: awk split records. (line 85) * record separators, regular expressions as: awk split records. - (line 124) + (line 125) * record separators, with multiline records: Multiple Line. (line 10) * records <1>: Basic High Level. (line 73) * records: Reading Files. (line 14) * records, multiline: Multiple Line. (line 6) * records, printing: Print. (line 22) * records, splitting input into: Records. (line 6) -* records, terminating: awk split records. (line 124) -* records, treating files as: gawk split records. (line 92) +* records, terminating: awk split records. (line 125) +* records, treating files as: gawk split records. (line 93) * recursive functions: Definition Syntax. (line 83) * redirect gawk output, in debugger: Debugger Info. (line 72) * redirection of input: Getline/File. (line 6) @@ -33459,7 +33792,7 @@ Index (line 77) * regexp: Regexp. (line 6) * regexp constants <1>: Comparison Operators. - (line 102) + (line 103) * regexp constants <2>: Regexp Constants. (line 6) * regexp constants: Regexp Usage. (line 57) * regexp constants, /=.../, /= operator and: Assignment Ops. (line 148) @@ -33478,7 +33811,7 @@ Index * regular expressions, as patterns <1>: Regexp Patterns. (line 6) * regular expressions, as patterns: Regexp Usage. (line 6) * regular expressions, as record separators: awk split records. - (line 124) + (line 125) * regular expressions, case sensitivity <1>: User-modified. (line 76) * regular expressions, case sensitivity: Case-sensitivity. (line 6) * regular expressions, computed: Computed Regexps. (line 6) @@ -33489,7 +33822,7 @@ Index (line 59) * regular expressions, gawk, command-line options: GNU Regexp Operators. (line 70) -* regular expressions, interval expressions and: Options. (line 277) +* regular expressions, interval expressions and: Options. (line 279) * regular expressions, leftmost longest match: Leftmost Longest. (line 6) * regular expressions, operators <1>: Regexp Operators. (line 6) @@ -33505,12 +33838,12 @@ Index * regular expressions, searching for: Egrep Program. (line 6) * relational operators, See comparison operators: Typing and Comparison. (line 9) -* replace in string: String Functions. (line 406) +* replace in string: String Functions. (line 407) * return debugger command: Debugger Execution Control. (line 54) * return statement, user-defined functions: Return Statement. (line 6) * return value, close() function: Close Files And Pipes. - (line 131) + (line 132) * rev() user-defined function: Function Example. (line 54) * revoutput extension: Extension Sample Revout. (line 11) @@ -33526,40 +33859,40 @@ Index (line 11) * right angle bracket (>), >> operator (I/O) <1>: Precedence. (line 65) * right angle bracket (>), >> operator (I/O): Redirection. (line 50) -* right shift: Bitwise Functions. (line 52) +* right shift: Bitwise Functions. (line 53) * right shift, bitwise: Bitwise Functions. (line 32) * Ritchie, Dennis: Basic Data Typing. (line 54) * RLENGTH variable: Auto-set. (line 259) -* RLENGTH variable, match() function and: String Functions. (line 224) +* RLENGTH variable, match() function and: String Functions. (line 227) * Robbins, Arnold <1>: Future Extensions. (line 6) -* Robbins, Arnold <2>: Bugs. (line 32) -* Robbins, Arnold <3>: Contributors. (line 141) +* Robbins, Arnold <2>: Bugs. (line 72) +* Robbins, Arnold <3>: Contributors. (line 144) * Robbins, Arnold <4>: General Data Types. (line 6) * Robbins, Arnold <5>: Alarm Program. (line 6) * Robbins, Arnold <6>: Passwd Functions. (line 90) * Robbins, Arnold <7>: Getline/Pipe. (line 39) * Robbins, Arnold: Command Line Field Separator. - (line 74) + (line 71) * Robbins, Bill: Getline/Pipe. (line 39) -* Robbins, Harry: Acknowledgments. (line 92) -* Robbins, Jean: Acknowledgments. (line 92) +* Robbins, Harry: Acknowledgments. (line 94) +* Robbins, Jean: Acknowledgments. (line 94) * Robbins, Miriam <1>: Passwd Functions. (line 90) * Robbins, Miriam <2>: Getline/Pipe. (line 39) -* Robbins, Miriam: Acknowledgments. (line 92) +* Robbins, Miriam: Acknowledgments. (line 94) * Rommel, Kai Uwe: Contributors. (line 42) * round to nearest integer: Numeric Functions. (line 38) * round() user-defined function: Round Function. (line 16) * rounding numbers: Round Function. (line 6) -* ROUNDMODE variable: User-modified. (line 128) -* RS variable <1>: User-modified. (line 133) +* ROUNDMODE variable: User-modified. (line 127) +* RS variable <1>: User-modified. (line 132) * RS variable: awk split records. (line 12) * RS variable, multiline records and: Multiple Line. (line 17) -* rshift: Bitwise Functions. (line 52) +* rshift: Bitwise Functions. (line 53) * RSTART variable: Auto-set. (line 265) -* RSTART variable, match() function and: String Functions. (line 224) +* RSTART variable, match() function and: String Functions. (line 227) * RT variable <1>: Auto-set. (line 272) * RT variable <2>: Multiple Line. (line 129) -* RT variable: awk split records. (line 124) +* RT variable: awk split records. (line 125) * Rubin, Paul <1>: Contributors. (line 15) * Rubin, Paul: History. (line 30) * rule, definition of: Getting Started. (line 21) @@ -33570,14 +33903,14 @@ Index (line 68) * sample debugging session: Sample Debugging Session. (line 6) -* sandbox mode: Options. (line 284) +* sandbox mode: Options. (line 286) * save debugger options: Debugger Info. (line 84) * scalar or array: Type Functions. (line 11) * scalar values: Basic Data Typing. (line 13) * scanning arrays: Scanning an Array. (line 6) * scanning multidimensional arrays: Multiscanning. (line 11) * Schorr, Andrew <1>: Contributors. (line 133) -* Schorr, Andrew <2>: Auto-set. (line 299) +* Schorr, Andrew <2>: Auto-set. (line 304) * Schorr, Andrew: Acknowledgments. (line 60) * Schreiber, Bert: Acknowledgments. (line 38) * Schreiber, Rita: Acknowledgments. (line 38) @@ -33609,12 +33942,12 @@ Index * separators, field, FIELDWIDTHS variable and: User-modified. (line 37) * separators, field, FPAT variable and: User-modified. (line 43) * separators, field, POSIX and: Fields. (line 6) -* separators, for records <1>: User-modified. (line 133) +* separators, for records <1>: User-modified. (line 132) * separators, for records: awk split records. (line 6) * separators, for records, regular expressions as: awk split records. - (line 124) + (line 125) * separators, for statements in actions: Action Overview. (line 19) -* separators, subscript: User-modified. (line 146) +* separators, subscript: User-modified. (line 145) * set breakpoint: Breakpoint Control. (line 11) * set debugger command: Viewing And Changing Data. (line 59) @@ -33623,7 +33956,7 @@ Index (line 67) * shadowing of variable values: Definition Syntax. (line 71) * shell quoting, rules for: Quoting. (line 6) -* shells, piping commands into: Redirection. (line 142) +* shells, piping commands into: Redirection. (line 136) * shells, quoting: Using Shell Variables. (line 12) * shells, quoting, rules for: Quoting. (line 18) @@ -33632,7 +33965,7 @@ Index * shells, variables: Using Shell Variables. (line 6) * shift, bitwise: Bitwise Functions. (line 32) -* short-circuit operators: Boolean Ops. (line 57) +* short-circuit operators: Boolean Ops. (line 59) * show all source files, in debugger: Debugger Info. (line 45) * show breakpoints: Debugger Info. (line 21) * show function arguments, in debugger: Debugger Info. (line 18) @@ -33658,27 +33991,27 @@ Index * sidebar, A Constant's Base Does Not Affect Its Value: Nondecimal-numbers. (line 64) * sidebar, Backslash Before Regular Characters: Escape Sequences. - (line 118) + (line 119) * sidebar, Changing FS Does Not Affect the Fields: Field Splitting Summary. (line 38) -* sidebar, Changing NR and FNR: Auto-set. (line 314) +* sidebar, Changing NR and FNR: Auto-set. (line 319) * sidebar, Controlling Output Buffering with system(): I/O Functions. - (line 138) + (line 137) * sidebar, Escape Sequences for Metacharacters: Escape Sequences. - (line 136) + (line 137) * sidebar, FS and IGNORECASE: Field Splitting Summary. (line 64) * sidebar, Interactive Versus Noninteractive Buffering: I/O Functions. - (line 107) -* sidebar, Matching the Null String: Gory Details. (line 141) + (line 106) +* sidebar, Matching the Null String: String Functions. (line 533) * sidebar, Operator Evaluation Order: Increment Ops. (line 58) -* sidebar, Piping into sh: Redirection. (line 140) +* sidebar, Piping into sh: Redirection. (line 134) * sidebar, Pre-POSIX awk Used OFMT For String Conversion: Strings And Numbers. (line 55) * sidebar, Recipe For A Programming Language: History. (line 6) * sidebar, RS = "\0" Is Not Portable: gawk split records. (line 63) * sidebar, So Why Does gawk have BEGINFILE and ENDFILE?: Filetrans Function. - (line 83) + (line 82) * sidebar, Syntactic Ambiguities Between /= and Regular Expressions: Assignment Ops. (line 146) * sidebar, Understanding #!: Executable Scripts. (line 31) @@ -33686,25 +34019,25 @@ Index * sidebar, Using \n in Bracket Expressions of Dynamic Regexps: Computed Regexps. (line 57) * sidebar, Using close()'s Return Value: Close Files And Pipes. - (line 129) -* SIGHUP signal, for dynamic profiling: Profiling. (line 211) -* SIGINT signal (MS-Windows): Profiling. (line 214) -* signals, HUP/SIGHUP, for profiling: Profiling. (line 211) -* signals, INT/SIGINT (MS-Windows): Profiling. (line 214) -* signals, QUIT/SIGQUIT (MS-Windows): Profiling. (line 214) -* signals, USR1/SIGUSR1, for profiling: Profiling. (line 188) + (line 130) +* SIGHUP signal, for dynamic profiling: Profiling. (line 210) +* SIGINT signal (MS-Windows): Profiling. (line 213) +* signals, HUP/SIGHUP, for profiling: Profiling. (line 210) +* signals, INT/SIGINT (MS-Windows): Profiling. (line 213) +* signals, QUIT/SIGQUIT (MS-Windows): Profiling. (line 213) +* signals, USR1/SIGUSR1, for profiling: Profiling. (line 187) * signature program: Signature Program. (line 6) -* SIGQUIT signal (MS-Windows): Profiling. (line 214) -* SIGUSR1 signal, for dynamic profiling: Profiling. (line 188) +* SIGQUIT signal (MS-Windows): Profiling. (line 213) +* SIGUSR1 signal, for dynamic profiling: Profiling. (line 187) * silent debugger command: Debugger Execution Control. (line 10) * sin: Numeric Functions. (line 91) * sine: Numeric Functions. (line 91) * single quote ('): One-shot. (line 15) -* single quote (') in gawk command lines: Long. (line 33) +* single quote (') in gawk command lines: Long. (line 35) * single quote ('), in shell commands: Quoting. (line 48) * single quote ('), vs. apostrophe: Comments. (line 27) -* single quote ('), with double quotes: Quoting. (line 70) +* single quote ('), with double quotes: Quoting. (line 73) * single-character fields: Single Character Fields. (line 6) * single-step execution, in the debugger: Debugger Execution Control. @@ -33714,8 +34047,8 @@ Index * sleep() extension function: Extension Sample Time. (line 22) * Solaris, POSIX-compliant awk: Other Versions. (line 96) -* sort array: String Functions. (line 42) -* sort array indices: String Functions. (line 42) +* sort array: String Functions. (line 41) +* sort array indices: String Functions. (line 41) * sort function, arrays, sorting: Array Sorting Functions. (line 6) * sort utility: Word Sorting. (line 50) @@ -33739,14 +34072,14 @@ Index * source files, search path for: Programs Exercises. (line 70) * sparse arrays: Array Intro. (line 72) * Spencer, Henry: Glossary. (line 11) -* split: String Functions. (line 313) -* split string into array: String Functions. (line 294) +* split: String Functions. (line 315) +* split string into array: String Functions. (line 296) * split utility: Split Program. (line 6) * split() function, array elements, deleting: Delete. (line 61) * split.awk program: Split Program. (line 30) -* sprintf <1>: String Functions. (line 381) +* sprintf <1>: String Functions. (line 382) * sprintf: OFMT. (line 15) -* sprintf() function, OFMT variable and: User-modified. (line 114) +* sprintf() function, OFMT variable and: User-modified. (line 113) * sprintf() function, print/printf statements and: Round Function. (line 6) * sqrt: Numeric Functions. (line 94) @@ -33782,18 +34115,18 @@ Index * string constants, vs. regexp constants: Computed Regexps. (line 39) * string extraction (internationalization): String Extraction. (line 6) -* string length: String Functions. (line 167) +* string length: String Functions. (line 170) * string operators: Concatenation. (line 8) -* string, regular expression match: String Functions. (line 207) +* string, regular expression match: String Functions. (line 210) * string-manipulation functions: String Functions. (line 6) * string-matching operators: Regexp Usage. (line 19) * string-translation functions: I18N Functions. (line 6) -* strings splitting, example: String Functions. (line 333) -* strings, converting <1>: Bitwise Functions. (line 109) +* strings splitting, example: String Functions. (line 334) +* strings, converting <1>: Bitwise Functions. (line 110) * strings, converting: Strings And Numbers. (line 6) -* strings, converting letter case: String Functions. (line 520) +* strings, converting letter case: String Functions. (line 521) * strings, converting, numbers to: User-modified. (line 30) -* strings, empty, See null strings: awk split records. (line 114) +* strings, empty, See null strings: awk split records. (line 115) * strings, extracting: String Extraction. (line 6) * strings, for localization: Programmer i18n. (line 14) * strings, length limitations: Scalar Constants. (line 20) @@ -33801,15 +34134,15 @@ Index * strings, null: Regexp Field Splitting. (line 43) * strings, numeric: Variable Typing. (line 6) -* strtonum: String Functions. (line 388) +* strtonum: String Functions. (line 389) * strtonum() function (gawk), --non-decimal-data option and: Nondecimal Data. - (line 36) -* sub <1>: String Functions. (line 406) + (line 35) +* sub <1>: String Functions. (line 407) * sub: Using Constant Regexps. (line 43) -* sub() function, arguments of: String Functions. (line 460) +* sub() function, arguments of: String Functions. (line 461) * sub() function, escape processing: Gory Details. (line 6) -* subscript separators: User-modified. (line 146) +* subscript separators: User-modified. (line 145) * subscripts in arrays, multidimensional: Multidimensional. (line 10) * subscripts in arrays, multidimensional, scanning: Multiscanning. (line 11) @@ -33817,30 +34150,30 @@ Index (line 6) * subscripts in arrays, uninitialized variables as: Uninitialized Subscripts. (line 6) -* SUBSEP variable: User-modified. (line 146) +* SUBSEP variable: User-modified. (line 145) * SUBSEP variable, and multidimensional arrays: Multidimensional. (line 16) * substitute in string: String Functions. (line 89) -* substr: String Functions. (line 479) -* substring: String Functions. (line 479) +* substr: String Functions. (line 480) +* substring: String Functions. (line 480) * Sumner, Andrew: Other Versions. (line 64) * supplementary groups of gawk process: Auto-set. (line 244) * switch statement: Switch Statement. (line 6) * SYMTAB array: Auto-set. (line 276) * syntactic ambiguity: /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) -* system: I/O Functions. (line 75) +* system: I/O Functions. (line 74) * systime: Time Functions. (line 66) * t debugger command (alias for tbreak): Breakpoint Control. (line 90) * tbreak debugger command: Breakpoint Control. (line 90) -* Tcl: Library Names. (line 57) +* Tcl: Library Names. (line 58) * TCP/IP: TCP/IP Networking. (line 6) * TCP/IP, support for: Special Network. (line 6) * tee utility: Tee Program. (line 6) * tee.awk program: Tee Program. (line 26) * temporary breakpoint: Breakpoint Control. (line 90) -* terminating records: awk split records. (line 124) -* testbits.awk program: Bitwise Functions. (line 70) +* terminating records: awk split records. (line 125) +* testbits.awk program: Bitwise Functions. (line 71) * testext extension: Extension Sample API Tests. (line 6) * Texinfo <1>: Adding Code. (line 100) @@ -33856,7 +34189,7 @@ Index * text, printing: Print. (line 22) * text, printing, unduplicated lines of: Uniq Program. (line 6) * TEXTDOMAIN variable <1>: Programmer i18n. (line 9) -* TEXTDOMAIN variable: User-modified. (line 152) +* TEXTDOMAIN variable: User-modified. (line 151) * TEXTDOMAIN variable, BEGIN pattern and: Programmer i18n. (line 60) * TEXTDOMAIN variable, portability and: I18N Portability. (line 20) * textdomain() function (C library): Explaining gettext. (line 28) @@ -33879,45 +34212,45 @@ Index * timestamps, converting dates to: Time Functions. (line 76) * timestamps, formatted: Getlocaltime Function. (line 6) -* tolower: String Functions. (line 521) -* toupper: String Functions. (line 527) +* tolower: String Functions. (line 522) +* toupper: String Functions. (line 528) * tr utility: Translate Program. (line 6) * trace debugger command: Miscellaneous Debugger Commands. (line 108) * traceback, display in debugger: Execution Stack. (line 13) * translate string: I18N Functions. (line 22) * translate.awk program: Translate Program. (line 55) -* treating files, as single records: gawk split records. (line 92) +* treating files, as single records: gawk split records. (line 93) * troubleshooting, --non-decimal-data option: Options. (line 211) * troubleshooting, == operator: Comparison Operators. (line 37) * troubleshooting, awk uses FS not IFS: Field Separators. (line 30) * troubleshooting, backslash before nonspecial character: Escape Sequences. - (line 120) + (line 121) * troubleshooting, division: Arithmetic Ops. (line 44) * troubleshooting, fatal errors, field widths, specifying: Constant Size. (line 23) * troubleshooting, fatal errors, printf format strings: Format Modifiers. - (line 159) -* troubleshooting, fflush() function: I/O Functions. (line 63) + (line 158) +* troubleshooting, fflush() function: I/O Functions. (line 62) * troubleshooting, function call syntax: Function Calls. (line 30) * troubleshooting, gawk: Compatibility Mode. (line 6) * troubleshooting, gawk, bug reports: Bugs. (line 9) * troubleshooting, gawk, fatal errors, function arguments: Calling Built-in. (line 16) * troubleshooting, getline function: File Checking. (line 25) -* troubleshooting, gsub()/sub() functions: String Functions. (line 470) -* troubleshooting, match() function: String Functions. (line 289) +* troubleshooting, gsub()/sub() functions: String Functions. (line 471) +* troubleshooting, match() function: String Functions. (line 291) * troubleshooting, print statement, omitting commas: Print Examples. (line 31) -* troubleshooting, printing: Redirection. (line 118) -* troubleshooting, quotes with file names: Special FD. (line 68) +* troubleshooting, printing: Redirection. (line 112) +* troubleshooting, quotes with file names: Special FD. (line 62) * troubleshooting, readable data files: File Checking. (line 6) * troubleshooting, regexp constants vs. string constants: Computed Regexps. (line 39) * troubleshooting, string concatenation: Concatenation. (line 26) -* troubleshooting, substr() function: String Functions. (line 497) -* troubleshooting, system() function: I/O Functions. (line 97) +* troubleshooting, substr() function: String Functions. (line 498) +* troubleshooting, system() function: I/O Functions. (line 96) * troubleshooting, typographical errors, global variables: Options. (line 98) * true, logical: Truth Values. (line 6) @@ -33949,11 +34282,11 @@ Index * uniq.awk program: Uniq Program. (line 65) * Unix: Glossary. (line 611) * Unix awk, backslashes in escape sequences: Escape Sequences. - (line 132) + (line 133) * Unix awk, close() function and: Close Files And Pipes. - (line 131) + (line 132) * Unix awk, password files, field separators and: Command Line Field Separator. - (line 65) + (line 62) * Unix, awk scripts and: Executable Scripts. (line 6) * UNIXROOT variable, on OS/2 systems: PC Using. (line 16) * unsigned integers: Computer Arithmetic. (line 41) @@ -33961,7 +34294,7 @@ Index (line 83) * unwatch debugger command: Viewing And Changing Data. (line 84) -* up debugger command: Execution Stack. (line 34) +* up debugger command: Execution Stack. (line 36) * user database, reading: Passwd Functions. (line 6) * user-defined functions: User-defined. (line 6) * user-defined, functions, counts, in a profile: Profiling. (line 137) @@ -33969,20 +34302,17 @@ Index * user-modifiable variables: User-modified. (line 6) * users, information about, printing: Id Program. (line 6) * users, information about, retrieving: Passwd Functions. (line 16) -* USR1 signal, for dynamic profiling: Profiling. (line 188) +* USR1 signal, for dynamic profiling: Profiling. (line 187) * values, numeric: Basic Data Typing. (line 13) * values, string: Basic Data Typing. (line 13) -* variable assignments and input files: Other Arguments. (line 23) +* variable assignments and input files: Other Arguments. (line 26) * variable typing: Typing and Comparison. (line 9) * variables <1>: Basic Data Typing. (line 6) * variables: Other Features. (line 6) * variables, assigning on command line: Assignment Options. (line 6) -* variables, built-in <1>: Built-in Variables. (line 6) * variables, built-in: Using Variables. (line 23) -* variables, built-in, -v option, setting with: Options. (line 40) -* variables, built-in, conveying information: Auto-set. (line 6) -* variables, flag: Boolean Ops. (line 67) +* variables, flag: Boolean Ops. (line 69) * variables, getline command into, using <1>: Getline/Variable/Coprocess. (line 6) * variables, getline command into, using <2>: Getline/Variable/Pipe. @@ -33994,7 +34324,9 @@ Index * variables, global, printing list of: Options. (line 93) * variables, initializing: Using Variables. (line 23) * variables, local to a function: Variable Scope. (line 6) -* variables, names of: Arrays. (line 18) +* variables, predefined: Built-in Variables. (line 6) +* variables, predefined -v option, setting with: Options. (line 40) +* variables, predefined conveying information: Auto-set. (line 6) * variables, private: Library Names. (line 11) * variables, setting: Options. (line 32) * variables, shadowing: Definition Syntax. (line 71) @@ -34015,7 +34347,7 @@ Index * vertical bar (|), |& operator (I/O) <2>: Precedence. (line 65) * vertical bar (|), |& operator (I/O): Getline/Coprocess. (line 6) * vertical bar (|), || operator <1>: Precedence. (line 89) -* vertical bar (|), || operator: Boolean Ops. (line 57) +* vertical bar (|), || operator: Boolean Ops. (line 59) * Vinschen, Corinna: Acknowledgments. (line 60) * w debugger command (alias for watch): Viewing And Changing Data. (line 67) @@ -34036,12 +34368,15 @@ Index * wc.awk program: Wc Program. (line 46) * Weinberger, Peter <1>: Contributors. (line 11) * Weinberger, Peter: History. (line 17) +* where debugger command: Execution Stack. (line 13) +* where debugger command (alias for backtrace): Execution Stack. + (line 13) * while statement: While Statement. (line 6) * while statement, use of regexps in: Regexp Usage. (line 19) * whitespace, as field separators: Default Field Splitting. (line 6) * whitespace, functions, calling: Calling Built-in. (line 10) -* whitespace, newlines as: Options. (line 258) +* whitespace, newlines as: Options. (line 260) * Williams, Kent: Contributors. (line 34) * Woehlke, Matthew: Contributors. (line 79) * Woods, John: Contributors. (line 27) @@ -34056,12 +34391,12 @@ Index * words, duplicate, searching for: Dupword Program. (line 6) * words, usage counts, generating: Word Sorting. (line 6) * writea() extension function: Extension Sample Read write array. - (line 9) + (line 12) * xgettext utility: String Extraction. (line 13) -* xor: Bitwise Functions. (line 55) +* xor: Bitwise Functions. (line 56) * XOR bitwise operation: Bitwise Functions. (line 6) * Yawitz, Efraim: Contributors. (line 131) -* Zaretskii, Eli <1>: Bugs. (line 71) +* Zaretskii, Eli <1>: Bugs. (line 72) * Zaretskii, Eli <2>: Contributors. (line 55) * Zaretskii, Eli: Acknowledgments. (line 60) * zerofile.awk program: Empty Files. (line 21) @@ -34075,12 +34410,12 @@ Index * | (vertical bar), | operator (I/O): Getline/Pipe. (line 9) * | (vertical bar), |& operator (I/O) <1>: Two-way I/O. (line 25) * | (vertical bar), |& operator (I/O) <2>: Precedence. (line 65) -* | (vertical bar), |& operator (I/O) <3>: Redirection. (line 102) +* | (vertical bar), |& operator (I/O) <3>: Redirection. (line 96) * | (vertical bar), |& operator (I/O): Getline/Coprocess. (line 6) * | (vertical bar), |& operator (I/O), pipes, closing: Close Files And Pipes. - (line 119) + (line 120) * | (vertical bar), || operator <1>: Precedence. (line 89) -* | (vertical bar), || operator: Boolean Ops. (line 57) +* | (vertical bar), || operator: Boolean Ops. (line 59) * ~ (tilde), ~ operator <1>: Expression Patterns. (line 24) * ~ (tilde), ~ operator <2>: Precedence. (line 80) * ~ (tilde), ~ operator <3>: Comparison Operators. @@ -34094,553 +34429,559 @@ Index Tag Table: Node: Top1204 -Node: Foreword41858 -Node: Preface46203 -Ref: Preface-Footnote-149226 -Ref: Preface-Footnote-249333 -Node: History49565 -Node: Names51939 -Ref: Names-Footnote-153033 -Node: This Manual53179 -Ref: This Manual-Footnote-158958 -Node: Conventions59058 -Node: Manual History61403 -Ref: Manual History-Footnote-164479 -Ref: Manual History-Footnote-264520 -Node: How To Contribute64594 -Node: Acknowledgments65833 -Node: Getting Started70581 -Node: Running gawk73015 -Node: One-shot74205 -Node: Read Terminal75430 -Node: Long77455 -Node: Executable Scripts78849 -Ref: Executable Scripts-Footnote-181650 -Node: Comments81752 -Node: Quoting84225 -Node: DOS Quoting89538 -Node: Sample Data Files90213 -Node: Very Simple92820 -Node: Two Rules97705 -Node: More Complex99599 -Ref: More Complex-Footnote-1102513 -Node: Statements/Lines102598 -Ref: Statements/Lines-Footnote-1107054 -Node: Other Features107319 -Node: When108250 -Ref: When-Footnote-1110006 -Node: Intro Summary110071 -Node: Invoking Gawk110954 -Node: Command Line112469 -Node: Options113260 -Ref: Options-Footnote-1128907 -Node: Other Arguments128932 -Node: Naming Standard Input131760 -Node: Environment Variables132853 -Node: AWKPATH Variable133411 -Ref: AWKPATH Variable-Footnote-1136277 -Ref: AWKPATH Variable-Footnote-2136322 -Node: AWKLIBPATH Variable136582 -Node: Other Environment Variables137341 -Node: Exit Status140793 -Node: Include Files141468 -Node: Loading Shared Libraries145046 -Node: Obsolete146430 -Node: Undocumented147127 -Node: Invoking Summary147394 -Node: Regexp148994 -Node: Regexp Usage150453 -Node: Escape Sequences152486 -Node: Regexp Operators158557 -Ref: Regexp Operators-Footnote-1165988 -Ref: Regexp Operators-Footnote-2166135 -Node: Bracket Expressions166233 -Ref: table-char-classes168251 -Node: Leftmost Longest171191 -Node: Computed Regexps172395 -Node: GNU Regexp Operators175773 -Node: Case-sensitivity179479 -Ref: Case-sensitivity-Footnote-1182369 -Ref: Case-sensitivity-Footnote-2182604 -Node: Regexp Summary182712 -Node: Reading Files184181 -Node: Records186273 -Node: awk split records186995 -Node: gawk split records191853 -Ref: gawk split records-Footnote-1196374 -Node: Fields196411 -Ref: Fields-Footnote-1199375 -Node: Nonconstant Fields199461 -Ref: Nonconstant Fields-Footnote-1201691 -Node: Changing Fields201893 -Node: Field Separators207847 -Node: Default Field Splitting210549 -Node: Regexp Field Splitting211666 -Node: Single Character Fields214993 -Node: Command Line Field Separator216052 -Node: Full Line Fields219478 -Ref: Full Line Fields-Footnote-1219986 -Node: Field Splitting Summary220032 -Ref: Field Splitting Summary-Footnote-1223164 -Node: Constant Size223265 -Node: Splitting By Content227871 -Ref: Splitting By Content-Footnote-1231944 -Node: Multiple Line231984 -Ref: Multiple Line-Footnote-1237840 -Node: Getline238019 -Node: Plain Getline240230 -Node: Getline/Variable242936 -Node: Getline/File244083 -Node: Getline/Variable/File245467 -Ref: Getline/Variable/File-Footnote-1247066 -Node: Getline/Pipe247153 -Node: Getline/Variable/Pipe249839 -Node: Getline/Coprocess250946 -Node: Getline/Variable/Coprocess252198 -Node: Getline Notes252935 -Node: Getline Summary255739 -Ref: table-getline-variants256147 -Node: Read Timeout257059 -Ref: Read Timeout-Footnote-1260886 -Node: Command-line directories260944 -Node: Input Summary261848 -Node: Input Exercises264985 -Node: Printing265713 -Node: Print267435 -Node: Print Examples268928 -Node: Output Separators271707 -Node: OFMT273723 -Node: Printf275081 -Node: Basic Printf275987 -Node: Control Letters277526 -Node: Format Modifiers281517 -Node: Printf Examples287544 -Node: Redirection290008 -Node: Special Files296980 -Node: Special FD297513 -Ref: Special FD-Footnote-1301110 -Node: Special Network301184 -Node: Special Caveats302034 -Node: Close Files And Pipes302830 -Ref: Close Files And Pipes-Footnote-1309991 -Ref: Close Files And Pipes-Footnote-2310139 -Node: Output Summary310289 -Node: Output Exercises311286 -Node: Expressions311966 -Node: Values313151 -Node: Constants313827 -Node: Scalar Constants314507 -Ref: Scalar Constants-Footnote-1315366 -Node: Nondecimal-numbers315616 -Node: Regexp Constants318616 -Node: Using Constant Regexps319141 -Node: Variables322213 -Node: Using Variables322868 -Node: Assignment Options324774 -Node: Conversion326649 -Node: Strings And Numbers327173 -Ref: Strings And Numbers-Footnote-1330235 -Node: Locale influences conversions330344 -Ref: table-locale-affects333061 -Node: All Operators333649 -Node: Arithmetic Ops334279 -Node: Concatenation336784 -Ref: Concatenation-Footnote-1339603 -Node: Assignment Ops339709 -Ref: table-assign-ops344692 -Node: Increment Ops345995 -Node: Truth Values and Conditions349433 -Node: Truth Values350516 -Node: Typing and Comparison351565 -Node: Variable Typing352358 -Node: Comparison Operators356010 -Ref: table-relational-ops356420 -Node: POSIX String Comparison359970 -Ref: POSIX String Comparison-Footnote-1361054 -Node: Boolean Ops361192 -Ref: Boolean Ops-Footnote-1365531 -Node: Conditional Exp365622 -Node: Function Calls367349 -Node: Precedence371229 -Node: Locales374898 -Node: Expressions Summary376529 -Node: Patterns and Actions379070 -Node: Pattern Overview380186 -Node: Regexp Patterns381863 -Node: Expression Patterns382406 -Node: Ranges386186 -Node: BEGIN/END389292 -Node: Using BEGIN/END390054 -Ref: Using BEGIN/END-Footnote-1392790 -Node: I/O And BEGIN/END392896 -Node: BEGINFILE/ENDFILE395167 -Node: Empty398098 -Node: Using Shell Variables398415 -Node: Action Overview400698 -Node: Statements403025 -Node: If Statement404873 -Node: While Statement406371 -Node: Do Statement408415 -Node: For Statement409571 -Node: Switch Statement412723 -Node: Break Statement415111 -Node: Continue Statement417152 -Node: Next Statement418977 -Node: Nextfile Statement421347 -Node: Exit Statement424004 -Node: Built-in Variables426408 -Node: User-modified427535 -Ref: User-modified-Footnote-1435224 -Node: Auto-set435286 -Ref: Auto-set-Footnote-1448475 -Ref: Auto-set-Footnote-2448680 -Node: ARGC and ARGV448736 -Node: Pattern Action Summary452640 -Node: Arrays454863 -Node: Array Basics456412 -Node: Array Intro457238 -Ref: figure-array-elements459211 -Ref: Array Intro-Footnote-1461735 -Node: Reference to Elements461863 -Node: Assigning Elements464313 -Node: Array Example464804 -Node: Scanning an Array466536 -Node: Controlling Scanning469537 -Ref: Controlling Scanning-Footnote-1474710 -Node: Delete475026 -Ref: Delete-Footnote-1477777 -Node: Numeric Array Subscripts477834 -Node: Uninitialized Subscripts480017 -Node: Multidimensional481644 -Node: Multiscanning484757 -Node: Arrays of Arrays486346 -Node: Arrays Summary491009 -Node: Functions493114 -Node: Built-in493987 -Node: Calling Built-in495065 -Node: Numeric Functions497053 -Ref: Numeric Functions-Footnote-1501889 -Ref: Numeric Functions-Footnote-2502246 -Ref: Numeric Functions-Footnote-3502294 -Node: String Functions502563 -Ref: String Functions-Footnote-1525560 -Ref: String Functions-Footnote-2525689 -Ref: String Functions-Footnote-3525937 -Node: Gory Details526024 -Ref: table-sub-escapes527797 -Ref: table-sub-proposed529317 -Ref: table-posix-sub530681 -Ref: table-gensub-escapes532221 -Ref: Gory Details-Footnote-1533397 -Node: I/O Functions533548 -Ref: I/O Functions-Footnote-1540658 -Node: Time Functions540805 -Ref: Time Functions-Footnote-1551269 -Ref: Time Functions-Footnote-2551337 -Ref: Time Functions-Footnote-3551495 -Ref: Time Functions-Footnote-4551606 -Ref: Time Functions-Footnote-5551718 -Ref: Time Functions-Footnote-6551945 -Node: Bitwise Functions552211 -Ref: table-bitwise-ops552773 -Ref: Bitwise Functions-Footnote-1557018 -Node: Type Functions557202 -Node: I18N Functions558344 -Node: User-defined559989 -Node: Definition Syntax560793 -Ref: Definition Syntax-Footnote-1566197 -Node: Function Example566266 -Ref: Function Example-Footnote-1568906 -Node: Function Caveats568928 -Node: Calling A Function569446 -Node: Variable Scope570401 -Node: Pass By Value/Reference573389 -Node: Return Statement576899 -Node: Dynamic Typing579883 -Node: Indirect Calls580812 -Ref: Indirect Calls-Footnote-1590528 -Node: Functions Summary590656 -Node: Library Functions593306 -Ref: Library Functions-Footnote-1596924 -Ref: Library Functions-Footnote-2597067 -Node: Library Names597238 -Ref: Library Names-Footnote-1600711 -Ref: Library Names-Footnote-2600931 -Node: General Functions601017 -Node: Strtonum Function602045 -Node: Assert Function604947 -Node: Round Function608273 -Node: Cliff Random Function609814 -Node: Ordinal Functions610830 -Ref: Ordinal Functions-Footnote-1613895 -Ref: Ordinal Functions-Footnote-2614147 -Node: Join Function614358 -Ref: Join Function-Footnote-1616129 -Node: Getlocaltime Function616329 -Node: Readfile Function620065 -Node: Data File Management621904 -Node: Filetrans Function622536 -Node: Rewind Function626605 -Node: File Checking628163 -Ref: File Checking-Footnote-1629295 -Node: Empty Files629496 -Node: Ignoring Assigns631475 -Node: Getopt Function633029 -Ref: Getopt Function-Footnote-1644293 -Node: Passwd Functions644496 -Ref: Passwd Functions-Footnote-1653475 -Node: Group Functions653563 -Ref: Group Functions-Footnote-1661494 -Node: Walking Arrays661707 -Node: Library Functions Summary663310 -Node: Library Exercises664698 -Node: Sample Programs665978 -Node: Running Examples666748 -Node: Clones667476 -Node: Cut Program668700 -Node: Egrep Program678558 -Ref: Egrep Program-Footnote-1686145 -Node: Id Program686255 -Node: Split Program689909 -Ref: Split Program-Footnote-1693447 -Node: Tee Program693575 -Node: Uniq Program696362 -Node: Wc Program703785 -Ref: Wc Program-Footnote-1708050 -Node: Miscellaneous Programs708142 -Node: Dupword Program709355 -Node: Alarm Program711386 -Node: Translate Program716190 -Ref: Translate Program-Footnote-1720763 -Ref: Translate Program-Footnote-2721033 -Node: Labels Program721172 -Ref: Labels Program-Footnote-1724533 -Node: Word Sorting724617 -Node: History Sorting728660 -Node: Extract Program730496 -Node: Simple Sed738032 -Node: Igawk Program741094 -Ref: Igawk Program-Footnote-1755398 -Ref: Igawk Program-Footnote-2755599 -Node: Anagram Program755737 -Node: Signature Program758805 -Node: Programs Summary760052 -Node: Programs Exercises761267 -Ref: Programs Exercises-Footnote-1765398 -Node: Advanced Features765489 -Node: Nondecimal Data767437 -Node: Array Sorting769014 -Node: Controlling Array Traversal769711 -Node: Array Sorting Functions777991 -Ref: Array Sorting Functions-Footnote-1781898 -Node: Two-way I/O782092 -Ref: Two-way I/O-Footnote-1787036 -Ref: Two-way I/O-Footnote-2787215 -Node: TCP/IP Networking787297 -Node: Profiling790139 -Node: Advanced Features Summary797690 -Node: Internationalization799554 -Node: I18N and L10N801034 -Node: Explaining gettext801720 -Ref: Explaining gettext-Footnote-1806746 -Ref: Explaining gettext-Footnote-2806930 -Node: Programmer i18n807095 -Ref: Programmer i18n-Footnote-1811889 -Node: Translator i18n811938 -Node: String Extraction812732 -Ref: String Extraction-Footnote-1813865 -Node: Printf Ordering813951 -Ref: Printf Ordering-Footnote-1816733 -Node: I18N Portability816797 -Ref: I18N Portability-Footnote-1819246 -Node: I18N Example819309 -Ref: I18N Example-Footnote-1822015 -Node: Gawk I18N822087 -Node: I18N Summary822725 -Node: Debugger824064 -Node: Debugging825086 -Node: Debugging Concepts825527 -Node: Debugging Terms827383 -Node: Awk Debugging829980 -Node: Sample Debugging Session830872 -Node: Debugger Invocation831392 -Node: Finding The Bug832728 -Node: List of Debugger Commands839207 -Node: Breakpoint Control840539 -Node: Debugger Execution Control844203 -Node: Viewing And Changing Data847563 -Node: Execution Stack850921 -Node: Debugger Info852434 -Node: Miscellaneous Debugger Commands856428 -Node: Readline Support861612 -Node: Limitations862504 -Node: Debugging Summary864777 -Node: Arbitrary Precision Arithmetic865945 -Node: Computer Arithmetic867432 -Ref: Computer Arithmetic-Footnote-1871819 -Node: Math Definitions871876 -Ref: table-ieee-formats875165 -Ref: Math Definitions-Footnote-1875705 -Node: MPFR features875808 -Node: FP Math Caution877425 -Ref: FP Math Caution-Footnote-1878475 -Node: Inexactness of computations878844 -Node: Inexact representation879792 -Node: Comparing FP Values881147 -Node: Errors accumulate882111 -Node: Getting Accuracy883544 -Node: Try To Round886203 -Node: Setting precision887102 -Ref: table-predefined-precision-strings887784 -Node: Setting the rounding mode889577 -Ref: table-gawk-rounding-modes889941 -Ref: Setting the rounding mode-Footnote-1893395 -Node: Arbitrary Precision Integers893574 -Ref: Arbitrary Precision Integers-Footnote-1897347 -Node: POSIX Floating Point Problems897496 -Ref: POSIX Floating Point Problems-Footnote-1901372 -Node: Floating point summary901410 -Node: Dynamic Extensions903614 -Node: Extension Intro905166 -Node: Plugin License906431 -Node: Extension Mechanism Outline907116 -Ref: figure-load-extension907540 -Ref: figure-load-new-function909025 -Ref: figure-call-new-function910027 -Node: Extension API Description912011 -Node: Extension API Functions Introduction913461 -Node: General Data Types918328 -Ref: General Data Types-Footnote-1924021 -Node: Requesting Values924320 -Ref: table-value-types-returned925057 -Node: Memory Allocation Functions926015 -Ref: Memory Allocation Functions-Footnote-1928762 -Node: Constructor Functions928858 -Node: Registration Functions930616 -Node: Extension Functions931301 -Node: Exit Callback Functions933603 -Node: Extension Version String934851 -Node: Input Parsers935501 -Node: Output Wrappers945315 -Node: Two-way processors949831 -Node: Printing Messages952035 -Ref: Printing Messages-Footnote-1953112 -Node: Updating `ERRNO'953264 -Node: Accessing Parameters954003 -Node: Symbol Table Access955233 -Node: Symbol table by name955747 -Node: Symbol table by cookie957723 -Ref: Symbol table by cookie-Footnote-1961856 -Node: Cached values961919 -Ref: Cached values-Footnote-1965423 -Node: Array Manipulation965514 -Ref: Array Manipulation-Footnote-1966612 -Node: Array Data Types966651 -Ref: Array Data Types-Footnote-1969354 -Node: Array Functions969446 -Node: Flattening Arrays973320 -Node: Creating Arrays980172 -Node: Extension API Variables984903 -Node: Extension Versioning985539 -Node: Extension API Informational Variables987440 -Node: Extension API Boilerplate988526 -Node: Finding Extensions992330 -Node: Extension Example992890 -Node: Internal File Description993620 -Node: Internal File Ops997711 -Ref: Internal File Ops-Footnote-11009143 -Node: Using Internal File Ops1009283 -Ref: Using Internal File Ops-Footnote-11011630 -Node: Extension Samples1011898 -Node: Extension Sample File Functions1013422 -Node: Extension Sample Fnmatch1020990 -Node: Extension Sample Fork1022472 -Node: Extension Sample Inplace1023685 -Node: Extension Sample Ord1025360 -Node: Extension Sample Readdir1026196 -Ref: table-readdir-file-types1027052 -Node: Extension Sample Revout1027851 -Node: Extension Sample Rev2way1028442 -Node: Extension Sample Read write array1029183 -Node: Extension Sample Readfile1031062 -Node: Extension Sample API Tests1032162 -Node: Extension Sample Time1032687 -Node: gawkextlib1034002 -Node: Extension summary1036815 -Node: Extension Exercises1040508 -Node: Language History1041230 -Node: V7/SVR3.11042873 -Node: SVR41045193 -Node: POSIX1046635 -Node: BTL1048021 -Node: POSIX/GNU1048755 -Node: Feature History1054531 -Node: Common Extensions1067622 -Node: Ranges and Locales1068934 -Ref: Ranges and Locales-Footnote-11073551 -Ref: Ranges and Locales-Footnote-21073578 -Ref: Ranges and Locales-Footnote-31073812 -Node: Contributors1074033 -Node: History summary1079458 -Node: Installation1080827 -Node: Gawk Distribution1081778 -Node: Getting1082262 -Node: Extracting1083086 -Node: Distribution contents1084728 -Node: Unix Installation1090498 -Node: Quick Installation1091115 -Node: Additional Configuration Options1093557 -Node: Configuration Philosophy1095295 -Node: Non-Unix Installation1097646 -Node: PC Installation1098104 -Node: PC Binary Installation1099415 -Node: PC Compiling1101263 -Ref: PC Compiling-Footnote-11104262 -Node: PC Testing1104367 -Node: PC Using1105543 -Node: Cygwin1109695 -Node: MSYS1110504 -Node: VMS Installation1111018 -Node: VMS Compilation1111814 -Ref: VMS Compilation-Footnote-11113036 -Node: VMS Dynamic Extensions1113094 -Node: VMS Installation Details1114467 -Node: VMS Running1116719 -Node: VMS GNV1119553 -Node: VMS Old Gawk1120276 -Node: Bugs1120746 -Node: Other Versions1124750 -Node: Installation summary1130974 -Node: Notes1132030 -Node: Compatibility Mode1132895 -Node: Additions1133677 -Node: Accessing The Source1134602 -Node: Adding Code1136038 -Node: New Ports1142216 -Node: Derived Files1146697 -Ref: Derived Files-Footnote-11152172 -Ref: Derived Files-Footnote-21152206 -Ref: Derived Files-Footnote-31152802 -Node: Future Extensions1152916 -Node: Implementation Limitations1153522 -Node: Extension Design1154770 -Node: Old Extension Problems1155924 -Ref: Old Extension Problems-Footnote-11157441 -Node: Extension New Mechanism Goals1157498 -Ref: Extension New Mechanism Goals-Footnote-11160858 -Node: Extension Other Design Decisions1161047 -Node: Extension Future Growth1163153 -Node: Old Extension Mechanism1163989 -Node: Notes summary1165751 -Node: Basic Concepts1166937 -Node: Basic High Level1167618 -Ref: figure-general-flow1167890 -Ref: figure-process-flow1168489 -Ref: Basic High Level-Footnote-11171718 -Node: Basic Data Typing1171903 -Node: Glossary1175231 -Node: Copying1200383 -Node: GNU Free Documentation License1237939 -Node: Index1263075 +Node: Foreword342225 +Node: Foreword446617 +Node: Preface48051 +Ref: Preface-Footnote-150922 +Ref: Preface-Footnote-251029 +Ref: Preface-Footnote-351262 +Node: History51404 +Node: Names53752 +Ref: Names-Footnote-154846 +Node: This Manual54992 +Ref: This Manual-Footnote-160821 +Node: Conventions60921 +Node: Manual History63261 +Ref: Manual History-Footnote-166252 +Ref: Manual History-Footnote-266293 +Node: How To Contribute66367 +Node: Acknowledgments67498 +Node: Getting Started72306 +Node: Running gawk74740 +Node: One-shot75930 +Node: Read Terminal77155 +Node: Long79182 +Node: Executable Scripts80698 +Ref: Executable Scripts-Footnote-183487 +Node: Comments83589 +Node: Quoting86062 +Node: DOS Quoting91568 +Node: Sample Data Files92243 +Node: Very Simple94836 +Node: Two Rules99727 +Node: More Complex101613 +Node: Statements/Lines104475 +Ref: Statements/Lines-Footnote-1108931 +Node: Other Features109196 +Node: When110127 +Ref: When-Footnote-1111883 +Node: Intro Summary111948 +Node: Invoking Gawk112831 +Node: Command Line114346 +Node: Options115137 +Ref: Options-Footnote-1130920 +Node: Other Arguments130945 +Node: Naming Standard Input133906 +Node: Environment Variables134999 +Node: AWKPATH Variable135557 +Ref: AWKPATH Variable-Footnote-1138967 +Ref: AWKPATH Variable-Footnote-2139012 +Node: AWKLIBPATH Variable139272 +Node: Other Environment Variables140528 +Node: Exit Status144019 +Node: Include Files144694 +Node: Loading Shared Libraries148282 +Node: Obsolete149709 +Node: Undocumented150406 +Node: Invoking Summary150673 +Node: Regexp152339 +Node: Regexp Usage153798 +Node: Escape Sequences155831 +Node: Regexp Operators162079 +Ref: Regexp Operators-Footnote-1169513 +Ref: Regexp Operators-Footnote-2169660 +Node: Bracket Expressions169758 +Ref: table-char-classes171775 +Node: Leftmost Longest174715 +Node: Computed Regexps176017 +Node: GNU Regexp Operators179414 +Node: Case-sensitivity183116 +Ref: Case-sensitivity-Footnote-1186006 +Ref: Case-sensitivity-Footnote-2186241 +Node: Regexp Summary186349 +Node: Reading Files187818 +Node: Records189912 +Node: awk split records190644 +Node: gawk split records195558 +Ref: gawk split records-Footnote-1200097 +Node: Fields200134 +Ref: Fields-Footnote-1202932 +Node: Nonconstant Fields203018 +Ref: Nonconstant Fields-Footnote-1205254 +Node: Changing Fields205456 +Node: Field Separators211388 +Node: Default Field Splitting214092 +Node: Regexp Field Splitting215209 +Node: Single Character Fields218559 +Node: Command Line Field Separator219618 +Node: Full Line Fields222830 +Ref: Full Line Fields-Footnote-1223338 +Node: Field Splitting Summary223384 +Ref: Field Splitting Summary-Footnote-1226515 +Node: Constant Size226616 +Node: Splitting By Content231222 +Ref: Splitting By Content-Footnote-1235295 +Node: Multiple Line235335 +Ref: Multiple Line-Footnote-1241224 +Node: Getline241403 +Node: Plain Getline243614 +Node: Getline/Variable246254 +Node: Getline/File247401 +Node: Getline/Variable/File248785 +Ref: Getline/Variable/File-Footnote-1250386 +Node: Getline/Pipe250473 +Node: Getline/Variable/Pipe253156 +Node: Getline/Coprocess254287 +Node: Getline/Variable/Coprocess255539 +Node: Getline Notes256278 +Node: Getline Summary259070 +Ref: table-getline-variants259482 +Node: Read Timeout260311 +Ref: Read Timeout-Footnote-1264125 +Node: Command-line directories264183 +Node: Input Summary265087 +Node: Input Exercises268339 +Node: Printing269067 +Node: Print270844 +Node: Print Examples272301 +Node: Output Separators275080 +Node: OFMT277098 +Node: Printf278452 +Node: Basic Printf279237 +Node: Control Letters280808 +Node: Format Modifiers284792 +Node: Printf Examples290799 +Node: Redirection293281 +Node: Special FD300120 +Ref: Special FD-Footnote-1303277 +Node: Special Files303351 +Node: Other Inherited Files303967 +Node: Special Network304967 +Node: Special Caveats305828 +Node: Close Files And Pipes306779 +Ref: Close Files And Pipes-Footnote-1313958 +Ref: Close Files And Pipes-Footnote-2314106 +Node: Output Summary314256 +Node: Output Exercises315252 +Node: Expressions315932 +Node: Values317117 +Node: Constants317793 +Node: Scalar Constants318473 +Ref: Scalar Constants-Footnote-1319332 +Node: Nondecimal-numbers319582 +Node: Regexp Constants322582 +Node: Using Constant Regexps323107 +Node: Variables326245 +Node: Using Variables326900 +Node: Assignment Options328810 +Node: Conversion330685 +Node: Strings And Numbers331209 +Ref: Strings And Numbers-Footnote-1334273 +Node: Locale influences conversions334382 +Ref: table-locale-affects337127 +Node: All Operators337715 +Node: Arithmetic Ops338345 +Node: Concatenation340850 +Ref: Concatenation-Footnote-1343669 +Node: Assignment Ops343775 +Ref: table-assign-ops348758 +Node: Increment Ops350036 +Node: Truth Values and Conditions353474 +Node: Truth Values354557 +Node: Typing and Comparison355606 +Node: Variable Typing356399 +Node: Comparison Operators360051 +Ref: table-relational-ops360461 +Node: POSIX String Comparison363976 +Ref: POSIX String Comparison-Footnote-1365048 +Node: Boolean Ops365186 +Ref: Boolean Ops-Footnote-1369665 +Node: Conditional Exp369756 +Node: Function Calls371483 +Node: Precedence375363 +Node: Locales379031 +Node: Expressions Summary380662 +Node: Patterns and Actions383236 +Node: Pattern Overview384356 +Node: Regexp Patterns386035 +Node: Expression Patterns386578 +Node: Ranges390358 +Node: BEGIN/END393464 +Node: Using BEGIN/END394226 +Ref: Using BEGIN/END-Footnote-1396963 +Node: I/O And BEGIN/END397069 +Node: BEGINFILE/ENDFILE399383 +Node: Empty402284 +Node: Using Shell Variables402601 +Node: Action Overview404877 +Node: Statements407204 +Node: If Statement409052 +Node: While Statement410550 +Node: Do Statement412578 +Node: For Statement413720 +Node: Switch Statement416875 +Node: Break Statement419263 +Node: Continue Statement421304 +Node: Next Statement423129 +Node: Nextfile Statement425509 +Node: Exit Statement428139 +Node: Built-in Variables430542 +Node: User-modified431675 +Ref: User-modified-Footnote-1439355 +Node: Auto-set439417 +Ref: Auto-set-Footnote-1452784 +Ref: Auto-set-Footnote-2452989 +Node: ARGC and ARGV453045 +Node: Pattern Action Summary457249 +Node: Arrays459676 +Node: Array Basics461005 +Node: Array Intro461849 +Ref: figure-array-elements463813 +Ref: Array Intro-Footnote-1466337 +Node: Reference to Elements466465 +Node: Assigning Elements468915 +Node: Array Example469406 +Node: Scanning an Array471164 +Node: Controlling Scanning474180 +Ref: Controlling Scanning-Footnote-1479369 +Node: Numeric Array Subscripts479685 +Node: Uninitialized Subscripts481870 +Node: Delete483487 +Ref: Delete-Footnote-1486231 +Node: Multidimensional486288 +Node: Multiscanning489383 +Node: Arrays of Arrays490972 +Node: Arrays Summary495733 +Node: Functions497838 +Node: Built-in498711 +Node: Calling Built-in499789 +Node: Numeric Functions501777 +Ref: Numeric Functions-Footnote-1506601 +Ref: Numeric Functions-Footnote-2506958 +Ref: Numeric Functions-Footnote-3507006 +Node: String Functions507275 +Ref: String Functions-Footnote-1530747 +Ref: String Functions-Footnote-2530876 +Ref: String Functions-Footnote-3531124 +Node: Gory Details531211 +Ref: table-sub-escapes532992 +Ref: table-sub-proposed534512 +Ref: table-posix-sub535876 +Ref: table-gensub-escapes537416 +Ref: Gory Details-Footnote-1538248 +Node: I/O Functions538399 +Ref: I/O Functions-Footnote-1545500 +Node: Time Functions545647 +Ref: Time Functions-Footnote-1556116 +Ref: Time Functions-Footnote-2556184 +Ref: Time Functions-Footnote-3556342 +Ref: Time Functions-Footnote-4556453 +Ref: Time Functions-Footnote-5556565 +Ref: Time Functions-Footnote-6556792 +Node: Bitwise Functions557058 +Ref: table-bitwise-ops557620 +Ref: Bitwise Functions-Footnote-1561928 +Node: Type Functions562097 +Node: I18N Functions563246 +Node: User-defined564891 +Node: Definition Syntax565695 +Ref: Definition Syntax-Footnote-1571101 +Node: Function Example571170 +Ref: Function Example-Footnote-1574087 +Node: Function Caveats574109 +Node: Calling A Function574627 +Node: Variable Scope575582 +Node: Pass By Value/Reference578570 +Node: Return Statement582080 +Node: Dynamic Typing585064 +Node: Indirect Calls585993 +Ref: Indirect Calls-Footnote-1597297 +Node: Functions Summary597425 +Node: Library Functions600124 +Ref: Library Functions-Footnote-1603742 +Ref: Library Functions-Footnote-2603885 +Node: Library Names604056 +Ref: Library Names-Footnote-1607516 +Ref: Library Names-Footnote-2607736 +Node: General Functions607822 +Node: Strtonum Function608925 +Node: Assert Function611945 +Node: Round Function615269 +Node: Cliff Random Function616810 +Node: Ordinal Functions617826 +Ref: Ordinal Functions-Footnote-1620891 +Ref: Ordinal Functions-Footnote-2621143 +Node: Join Function621354 +Ref: Join Function-Footnote-1623125 +Node: Getlocaltime Function623325 +Node: Readfile Function627066 +Node: Shell Quoting629036 +Node: Data File Management630437 +Node: Filetrans Function631069 +Node: Rewind Function635128 +Node: File Checking636513 +Ref: File Checking-Footnote-1637841 +Node: Empty Files638042 +Node: Ignoring Assigns640021 +Node: Getopt Function641572 +Ref: Getopt Function-Footnote-1653032 +Node: Passwd Functions653235 +Ref: Passwd Functions-Footnote-1662086 +Node: Group Functions662174 +Ref: Group Functions-Footnote-1670077 +Node: Walking Arrays670290 +Node: Library Functions Summary671893 +Node: Library Exercises673294 +Node: Sample Programs674574 +Node: Running Examples675344 +Node: Clones676072 +Node: Cut Program677296 +Node: Egrep Program687026 +Ref: Egrep Program-Footnote-1694530 +Node: Id Program694640 +Node: Split Program698284 +Ref: Split Program-Footnote-1701730 +Node: Tee Program701858 +Node: Uniq Program704645 +Node: Wc Program712066 +Ref: Wc Program-Footnote-1716314 +Node: Miscellaneous Programs716406 +Node: Dupword Program717619 +Node: Alarm Program719650 +Node: Translate Program724454 +Ref: Translate Program-Footnote-1729018 +Node: Labels Program729288 +Ref: Labels Program-Footnote-1732637 +Node: Word Sorting732721 +Node: History Sorting736791 +Node: Extract Program738627 +Node: Simple Sed746159 +Node: Igawk Program749221 +Ref: Igawk Program-Footnote-1763547 +Ref: Igawk Program-Footnote-2763748 +Ref: Igawk Program-Footnote-3763870 +Node: Anagram Program763985 +Node: Signature Program767047 +Node: Programs Summary768294 +Node: Programs Exercises769487 +Ref: Programs Exercises-Footnote-1773618 +Node: Advanced Features773709 +Node: Nondecimal Data775657 +Node: Array Sorting777247 +Node: Controlling Array Traversal777944 +Ref: Controlling Array Traversal-Footnote-1786275 +Node: Array Sorting Functions786393 +Ref: Array Sorting Functions-Footnote-1790285 +Node: Two-way I/O790479 +Ref: Two-way I/O-Footnote-1795423 +Ref: Two-way I/O-Footnote-2795609 +Node: TCP/IP Networking795691 +Node: Profiling798563 +Node: Advanced Features Summary806837 +Node: Internationalization808770 +Node: I18N and L10N810250 +Node: Explaining gettext810936 +Ref: Explaining gettext-Footnote-1815965 +Ref: Explaining gettext-Footnote-2816149 +Node: Programmer i18n816314 +Ref: Programmer i18n-Footnote-1821180 +Node: Translator i18n821229 +Node: String Extraction822023 +Ref: String Extraction-Footnote-1823154 +Node: Printf Ordering823240 +Ref: Printf Ordering-Footnote-1826026 +Node: I18N Portability826090 +Ref: I18N Portability-Footnote-1828539 +Node: I18N Example828602 +Ref: I18N Example-Footnote-1831402 +Node: Gawk I18N831474 +Node: I18N Summary832112 +Node: Debugger833451 +Node: Debugging834473 +Node: Debugging Concepts834914 +Node: Debugging Terms836771 +Node: Awk Debugging839346 +Node: Sample Debugging Session840238 +Node: Debugger Invocation840758 +Node: Finding The Bug842142 +Node: List of Debugger Commands848617 +Node: Breakpoint Control849949 +Node: Debugger Execution Control853641 +Node: Viewing And Changing Data857005 +Node: Execution Stack860370 +Node: Debugger Info862008 +Node: Miscellaneous Debugger Commands866025 +Node: Readline Support871217 +Node: Limitations872109 +Node: Debugging Summary874206 +Node: Arbitrary Precision Arithmetic875374 +Node: Computer Arithmetic876790 +Ref: table-numeric-ranges880391 +Ref: Computer Arithmetic-Footnote-1881250 +Node: Math Definitions881307 +Ref: table-ieee-formats884594 +Ref: Math Definitions-Footnote-1885198 +Node: MPFR features885303 +Node: FP Math Caution886974 +Ref: FP Math Caution-Footnote-1888024 +Node: Inexactness of computations888393 +Node: Inexact representation889341 +Node: Comparing FP Values890696 +Node: Errors accumulate891769 +Node: Getting Accuracy893202 +Node: Try To Round895861 +Node: Setting precision896760 +Ref: table-predefined-precision-strings897444 +Node: Setting the rounding mode899238 +Ref: table-gawk-rounding-modes899602 +Ref: Setting the rounding mode-Footnote-1903056 +Node: Arbitrary Precision Integers903235 +Ref: Arbitrary Precision Integers-Footnote-1908139 +Node: POSIX Floating Point Problems908288 +Ref: POSIX Floating Point Problems-Footnote-1912164 +Node: Floating point summary912202 +Node: Dynamic Extensions914394 +Node: Extension Intro915946 +Node: Plugin License917212 +Node: Extension Mechanism Outline918009 +Ref: figure-load-extension918437 +Ref: figure-register-new-function919917 +Ref: figure-call-new-function920921 +Node: Extension API Description922907 +Node: Extension API Functions Introduction924357 +Node: General Data Types929193 +Ref: General Data Types-Footnote-1934880 +Node: Memory Allocation Functions935179 +Ref: Memory Allocation Functions-Footnote-1938009 +Node: Constructor Functions938105 +Node: Registration Functions939839 +Node: Extension Functions940524 +Node: Exit Callback Functions942820 +Node: Extension Version String944068 +Node: Input Parsers944718 +Node: Output Wrappers954533 +Node: Two-way processors959049 +Node: Printing Messages961253 +Ref: Printing Messages-Footnote-1962330 +Node: Updating `ERRNO'962482 +Node: Requesting Values963222 +Ref: table-value-types-returned963950 +Node: Accessing Parameters964908 +Node: Symbol Table Access966139 +Node: Symbol table by name966653 +Node: Symbol table by cookie968633 +Ref: Symbol table by cookie-Footnote-1972772 +Node: Cached values972835 +Ref: Cached values-Footnote-1976339 +Node: Array Manipulation976430 +Ref: Array Manipulation-Footnote-1977528 +Node: Array Data Types977567 +Ref: Array Data Types-Footnote-1980224 +Node: Array Functions980316 +Node: Flattening Arrays984170 +Node: Creating Arrays991057 +Node: Extension API Variables995824 +Node: Extension Versioning996460 +Node: Extension API Informational Variables998361 +Node: Extension API Boilerplate999449 +Node: Finding Extensions1003265 +Node: Extension Example1003825 +Node: Internal File Description1004597 +Node: Internal File Ops1008664 +Ref: Internal File Ops-Footnote-11020322 +Node: Using Internal File Ops1020462 +Ref: Using Internal File Ops-Footnote-11022845 +Node: Extension Samples1023118 +Node: Extension Sample File Functions1024642 +Node: Extension Sample Fnmatch1032244 +Node: Extension Sample Fork1033726 +Node: Extension Sample Inplace1034939 +Node: Extension Sample Ord1036614 +Node: Extension Sample Readdir1037450 +Ref: table-readdir-file-types1038326 +Node: Extension Sample Revout1039137 +Node: Extension Sample Rev2way1039728 +Node: Extension Sample Read write array1040469 +Node: Extension Sample Readfile1042408 +Node: Extension Sample Time1043503 +Node: Extension Sample API Tests1044852 +Node: gawkextlib1045343 +Node: Extension summary1047993 +Node: Extension Exercises1051675 +Node: Language History1052397 +Node: V7/SVR3.11054054 +Node: SVR41056235 +Node: POSIX1057680 +Node: BTL1059069 +Node: POSIX/GNU1059803 +Node: Feature History1065432 +Node: Common Extensions1078530 +Node: Ranges and Locales1079854 +Ref: Ranges and Locales-Footnote-11084493 +Ref: Ranges and Locales-Footnote-21084520 +Ref: Ranges and Locales-Footnote-31084754 +Node: Contributors1084975 +Node: History summary1090515 +Node: Installation1091884 +Node: Gawk Distribution1092840 +Node: Getting1093324 +Node: Extracting1094148 +Node: Distribution contents1095790 +Node: Unix Installation1101855 +Node: Quick Installation1102538 +Node: Shell Startup Files1104956 +Node: Additional Configuration Options1106035 +Node: Configuration Philosophy1107776 +Node: Non-Unix Installation1110127 +Node: PC Installation1110585 +Node: PC Binary Installation1111911 +Node: PC Compiling1113759 +Ref: PC Compiling-Footnote-11116780 +Node: PC Testing1116885 +Node: PC Using1118061 +Node: Cygwin1122176 +Node: MSYS1122999 +Node: VMS Installation1123497 +Node: VMS Compilation1124289 +Ref: VMS Compilation-Footnote-11125511 +Node: VMS Dynamic Extensions1125569 +Node: VMS Installation Details1127253 +Node: VMS Running1129505 +Node: VMS GNV1132346 +Node: VMS Old Gawk1133080 +Node: Bugs1133550 +Node: Other Versions1137454 +Node: Installation summary1143667 +Node: Notes1144723 +Node: Compatibility Mode1145588 +Node: Additions1146370 +Node: Accessing The Source1147295 +Node: Adding Code1148731 +Node: New Ports1154903 +Node: Derived Files1159385 +Ref: Derived Files-Footnote-11164860 +Ref: Derived Files-Footnote-21164894 +Ref: Derived Files-Footnote-31165490 +Node: Future Extensions1165604 +Node: Implementation Limitations1166210 +Node: Extension Design1167458 +Node: Old Extension Problems1168612 +Ref: Old Extension Problems-Footnote-11170129 +Node: Extension New Mechanism Goals1170186 +Ref: Extension New Mechanism Goals-Footnote-11173546 +Node: Extension Other Design Decisions1173735 +Node: Extension Future Growth1175843 +Node: Old Extension Mechanism1176679 +Node: Notes summary1178441 +Node: Basic Concepts1179627 +Node: Basic High Level1180308 +Ref: figure-general-flow1180580 +Ref: figure-process-flow1181179 +Ref: Basic High Level-Footnote-11184408 +Node: Basic Data Typing1184593 +Node: Glossary1187921 +Node: Copying1213079 +Node: GNU Free Documentation License1250635 +Node: Index1275771 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 17972c7a..e97b88b6 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -37,13 +37,11 @@ @ifnotdocbook @set BULLET @bullet{} @set MINUS @minus{} -@set NUL @sc{nul} @end ifnotdocbook @ifdocbook @set BULLET @set MINUS -@set NUL NUL @end ifdocbook @set xref-automatic-section-title @@ -53,11 +51,16 @@ @c applies to and all the info about who's publishing this edition @c These apply across the board. -@set UPDATE-MONTH August, 2014 +@set UPDATE-MONTH September, 2014 @set VERSION 4.1 -@set PATCHLEVEL 1 +@set PATCHLEVEL 2 +@ifset FOR_PRINT +@set TITLE Effective AWK Programming +@end ifset +@ifclear FOR_PRINT @set TITLE GAWK: Effective AWK Programming +@end ifclear @set SUBTITLE A User's Guide for GNU Awk @set EDITION 4.1 @@ -428,8 +431,9 @@ particular records in a file and perform operations upon them. @end ifnottex @menu -* Foreword:: Some nice words about this +* Foreword3:: Some nice words about this @value{DOCUMENT}. +* Foreword4:: More nice words. * Preface:: What this @value{DOCUMENT} is about; brief history and acknowledgments. * Getting Started:: A basic introduction to using @@ -560,8 +564,8 @@ particular records in a file and perform operations upon them. * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting @code{FS} from the - command line. +* Command Line Field Separator:: Setting @code{FS} from the command + line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -605,10 +609,12 @@ particular records in a file and perform operations upon them. * Printf Examples:: Several examples. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in @command{gawk}. @command{gawk} allows access to inherited file descriptors. -* Special FD:: Special files for I/O. +* Other Inherited Files:: Accessing other open files with + @command{gawk}. * Special Network:: Special files for network communications. * Special Caveats:: Things to watch out for. @@ -701,7 +707,7 @@ particular records in a file and perform operations upon them. record. * Nextfile Statement:: Stop processing the current file. * Exit Statement:: Stop execution of @command{awk}. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * User-modified:: Built-in variables that you change to control @command{awk}. * Auto-set:: Built-in variables where @command{awk} @@ -721,12 +727,12 @@ particular records in a file and perform operations upon them. elements. * Controlling Scanning:: Controlling the order in which arrays are scanned. -* Delete:: The @code{delete} statement removes an - element from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in @command{awk}. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The @code{delete} statement removes an + element from an array. * Multidimensional:: Emulating multidimensional arrays in @command{awk}. * Multiscanning:: Scanning multidimensional arrays. @@ -785,6 +791,8 @@ particular records in a file and perform operations upon them. * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the + shell. * Data File Management:: Functions for managing command-line data files. * Filetrans Function:: A function for handling data file @@ -899,7 +907,6 @@ particular records in a file and perform operations upon them. * Extension API Description:: A full description of the API. * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with @@ -912,6 +919,7 @@ particular records in a file and perform operations upon them. * Two-way processors:: Registering a two-way processor. * Printing Messages:: Functions for printing messages. * Updating @code{ERRNO}:: Functions for updating @code{ERRNO}. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -950,9 +958,9 @@ particular records in a file and perform operations upon them. processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to @code{gettimeofday()} and @code{sleep()}. +* Extension Sample API Tests:: Tests for the API. * gawkextlib:: The @code{gawkextlib} project. * Extension summary:: Extension summary. * Extension Exercises:: Exercises. @@ -981,6 +989,7 @@ particular records in a file and perform operations upon them. * Unix Installation:: Installing @command{gawk} under various versions of Unix. * Quick Installation:: Compiling @command{gawk} under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. * Non-Unix Installation:: Installation on Other Operating @@ -1053,8 +1062,8 @@ for enrichening our lives in innumerable ways. @summarycontents @contents -@node Foreword -@unnumbered Foreword +@node Foreword3 +@unnumbered Foreword to the Third Edition @c This bit is post-processed by a script which turns the chapter @c tag into a preface tag, and moves this stuff to before the title. @@ -1088,7 +1097,7 @@ books on Unix, I found the gray AWK book, a.k.a.@: Aho, Kernighan and Weinberger, @cite{The AWK Programming Language}, Addison-Wesley, 1988. AWK's simple programming paradigm---find a pattern in the input and then perform an action---often reduced complex or tedious -data manipulations to few lines of code. I was excited to try my +data manipulations to a few lines of code. I was excited to try my hand at programming in AWK. Alas, the @command{awk} on my computer was a limited version of the @@ -1204,6 +1213,58 @@ March, 2001 @end display @end ifnotdocbook +@node Foreword4 +@unnumbered Foreword to the Fourth Edition + +@c This bit is post-processed by a script which turns the chapter +@c tag into a preface tag, and moves this stuff to before the title. +@c Bleah. +@docbook + <prefaceinfo> + <author> + <firstname>Michael</firstname> + <surname>Brennan</surname> + <!-- can't put mawk into command tags. sigh. --> + <affiliation><jobtitle>Author of mawk</jobtitle></affiliation> + </author> + <date>October, 2014</date> + </prefaceinfo> +@end docbook + +Some things don't change. Thirteen years ago I wrote: +``If you use AWK or want to learn how, then read this book.'' +True then and still true today. + +Learning to use a programming language is more than mastering the +syntax. One needs to acquire an understanding of how to use the +features of the language to solve practical programming problems. +A focus of this book is many examples that show how to use AWK. + +Some things do change. Our computers are much faster and have more memory. +Consequently, speed and storage inefficiencies of a high level language +matter less. Prototyping in AWK and then rewriting in C for performance +reasons happens less, because more often the prototype is fast enough. + +Of course, there are computing operations that are best done in C or C++. +With @command{gawk} 4.1 and later, you do not have to choose between writing +your program in AWK or in C/C++. You can write most of your +program in AWK and the aspects that require C/C++ capabilities can be written +in C/C++ and then the pieces glued together when the @command{gawk} module loads +the C/C++ module as a dynamic plug-in. +@c Chapter 16 +@ref{Dynamic Extensions}, +has all the +details, and as expected, many examples to help you learn the ins and outs. + +@ifnotdocbook +@cindex Brennan, Michael +@display +Michael Brennan +Author of @command{mawk} +October, 2014 +@end display +@end ifnotdocbook + @node Preface @unnumbered Preface @c I saw a comment somewhere that the preface should describe the book itself, @@ -1222,7 +1283,7 @@ March, 2001 <affiliation><jobtitle>Nof Ayalon</jobtitle></affiliation> <affiliation><jobtitle>ISRAEL</jobtitle></affiliation> </author> - <date>June, 2014</date> + <date>December, 2014</date> </prefaceinfo> @end docbook @@ -1235,8 +1296,7 @@ language that makes it easy to handle simple data-reformatting jobs. The GNU implementation of @command{awk} is called @command{gawk}; if you invoke it with the proper options or environment variables -(@pxref{Options}), it is fully -compatible with +it is fully compatible with the POSIX@footnote{The 2008 POSIX standard is accessible online at @w{@url{http://www.opengroup.org/onlinepubs/9699919799/}.}} specification of the @command{awk} language @@ -1244,7 +1304,7 @@ and with the Unix version of @command{awk} maintained by Brian Kernighan. This means that all properly written @command{awk} programs should work with @command{gawk}. -Thus, we usually don't distinguish between @command{gawk} and other +So most of the time, we don't distinguish between @command{gawk} and other @command{awk} implementations. @cindex @command{awk}, POSIX and, See Also POSIX @command{awk} @@ -1253,7 +1313,7 @@ Thus, we usually don't distinguish between @command{gawk} and other @cindex @command{gawk}, @command{awk} and @cindex @command{awk}, @command{gawk} and @cindex @command{awk}, uses for -Using @command{awk} allows you to: +Using @command{awk} you can: @itemize @value{BULLET} @item @@ -1291,15 +1351,15 @@ Sort data Perform simple network communications @item -Profile and debug @command{awk} programs. +Profile and debug @command{awk} programs @item -Extend the language with functions written in C or C++. +Extend the language with functions written in C or C++ @end itemize This @value{DOCUMENT} teaches you about the @command{awk} language and how you can use it effectively. You should already be familiar with basic -system commands, such as @command{cat} and @command{ls},@footnote{These commands +system commands, such as @command{cat} and @command{ls},@footnote{These utilities are available on POSIX-compliant systems, as well as on traditional Unix-based systems. If you are using some other operating system, you still need to be familiar with the ideas of I/O redirection and pipes.} as well as basic shell @@ -1321,10 +1381,9 @@ Microsoft Windows @ifclear FOR_PRINT (all versions) and OS/2 PCs, @end ifclear -and OpenVMS. -(Some other, obsolete systems to which @command{gawk} was once ported -are no longer supported and the code for those systems -has been removed.) +and OpenVMS.@footnote{Some other, obsolete systems to which @command{gawk} +was once ported are no longer supported and the code for those systems +has been removed.} @menu * History:: The history of @command{gawk} and @@ -1401,13 +1460,13 @@ The version in System V Release 4 (1989) added some new features and cleaned up the behavior in some of the ``dark corners'' of the language. The specification for @command{awk} in the POSIX Command Language and Utilities standard further clarified the language. -Both the @command{gawk} designers and the original Bell Laboratories @command{awk} -designers provided feedback for the POSIX specification. +Both the @command{gawk} designers and the original @command{awk} designers at Bell Laboratories +provided feedback for the POSIX specification. @cindex Rubin, Paul @cindex Fenlason, Jay @cindex Trueman, David -Paul Rubin wrote the GNU implementation, @command{gawk}, in 1986. +Paul Rubin wrote @command{gawk} in 1986. Jay Fenlason completed it, with advice from Richard Stallman. John Woods contributed parts of the code as well. In 1988 and 1989, David Trueman, with help from me, thoroughly reworked @command{gawk} for compatibility @@ -1430,7 +1489,7 @@ an @command{awk}-level debugger. This version became available as @command{gawk} @value{PVERSION} 4.0, in 2011. @xref{Contributors}, -for a complete list of those who made important contributions to @command{gawk}. +for a full list of those who made important contributions to @command{gawk}. @node Names @unnumberedsec A Rose by Any Other Name @@ -1496,8 +1555,8 @@ entry ``differences in @command{awk} and @command{gawk}.''} @ifset FOR_PRINT implementations. @end ifset -Finally, any @command{gawk} features that are not in -the POSIX standard for @command{awk} are noted. +Finally, it notes any @command{gawk} features that are not in +the POSIX standard for @command{awk}. @ifnotinfo This @value{DOCUMENT} has the difficult task of being both a tutorial and a reference. @@ -1516,7 +1575,7 @@ All appear in the index, under the heading ``sidebar.'' Most of the time, the examples use complete @command{awk} programs. Some of the more advanced sections show only the part of the @command{awk} -program that illustrates the concept currently being described. +program that illustrates the concept being described. While this @value{DOCUMENT} is aimed principally at people who have not been exposed @@ -1564,7 +1623,7 @@ for getting most things done in a program. @ref{Patterns and Actions}, describes how to write patterns for matching records, actions for -doing something when a record is matched, and the built-in variables +doing something when a record is matched, and the predefined variables @command{awk} and @command{gawk} use. @ref{Arrays}, @@ -1574,9 +1633,9 @@ sorting arrays in @command{gawk}. It also describes how @command{gawk} provides arrays of arrays. @ref{Functions}, -describes the built-in functions @command{awk} and -@command{gawk} provide, as well as how to define -your own functions. +describes the built-in functions @command{awk} and @command{gawk} provide, +as well as how to define your own functions. It also discusses how +@command{gawk} lets you call functions indirectly. Part II shows how to use @command{awk} and @command{gawk} for problem solving. There is lots of code here for you to read and learn from. @@ -1595,21 +1654,21 @@ Part III focuses on features specific to @command{gawk}. It contains the following chapters: @ref{Advanced Features}, -describes a number of @command{gawk}-specific advanced features. +describes a number of advanced features. Of particular note -are the abilities to have two-way communications with another process, +are the abilities to control the order of array traversal, +have two-way communications with another process, perform TCP/IP networking, and profile your @command{awk} programs. @ref{Internationalization}, -describes special features in @command{gawk} for translating program +describes special features for translating program messages into different languages at runtime. -@ref{Debugger}, describes the @command{awk} debugger. +@ref{Debugger}, describes the @command{gawk} debugger. @ref{Arbitrary Precision Arithmetic}, -describes advanced arithmetic facilities provided by -@command{gawk}. +describes advanced arithmetic facilities. @ref{Dynamic Extensions}, describes how to add new variables and functions to @command{gawk} by writing extensions in C or C++. @@ -1649,9 +1708,10 @@ printed edition. You may find them online, as follows: @uref{http://www.gnu.org/software/gawk/manual/html_node/Notes.html, The appendix on implementation notes} -describes how to disable @command{gawk}'s extensions, as -well as how to contribute new code to @command{gawk}, -and some possible future directions for @command{gawk} development. +describes how to disable @command{gawk}'s extensions, how to contribute +new code to @command{gawk}, where to find information on some possible +future directions for @command{gawk} development, and the design decisions +behind the extension API. @uref{http://www.gnu.org/software/gawk/manual/html_node/Basic-Concepts.html, The appendix on basic concepts} @@ -1669,7 +1729,7 @@ The GNU FDL} is the license that covers this @value{DOCUMENT}. Some of the chapters have exercise sections; these have also been -omitted from the print edition. +omitted from the print edition but are available online. @end ifset @ifclear FOR_PRINT @@ -1791,8 +1851,8 @@ the picture of a flashlight in the margin, as shown here. They also appear in the index under the heading ``dark corner.'' @end ifclear -As noted by the opening quote, though, any coverage of dark corners is, -by definition, incomplete. +But, as noted by the opening quote, any coverage of dark +corners is by definition incomplete. @cindex c.e., See common extensions Extensions to the standard @command{awk} language that are supported by @@ -1866,9 +1926,7 @@ available for download from the Internet. @ifnotinfo The @value{DOCUMENT} you are reading is actually free---at least, the information in it is free to anyone. The machine-readable -source code for the @value{DOCUMENT} comes with @command{gawk}; anyone -may take this @value{DOCUMENT} to a copying machine and make as many -copies as they like. +source code for the @value{DOCUMENT} comes with @command{gawk}. @ifclear FOR_PRINT (Take a moment to check the Free Documentation License in @ref{GNU Free Documentation License}.) @@ -1876,7 +1934,7 @@ License in @ref{GNU Free Documentation License}.) @end ifnotinfo @cindex Close, Diane -The @value{DOCUMENT} itself has gone through a number of previous editions. +The @value{DOCUMENT} itself has gone through multiple previous editions. Paul Rubin wrote the very first draft of @cite{The GAWK Manual}; it was around 40 pages in size. Diane Close and Richard Stallman improved it, yielding a @@ -1892,15 +1950,14 @@ The FSF published the first two editions under the title @cite{The GNU Awk User's Guide}. @ifset FOR_PRINT SSC published two editions of the @value{DOCUMENT} under the -title @cite{Effective awk Programming}, and in O'Reilly published +title @cite{Effective awk Programming}, and O'Reilly published the third edition in 2001. @end ifset This edition maintains the basic structure of the previous editions. -For FSF edition 4.0, the content has been thoroughly reviewed -and updated. All references to @command{gawk} versions prior to 4.0 have been -removed. -Of significant note for this edition was @ref{Debugger}. +For FSF edition 4.0, the content was thoroughly reviewed and updated. All +references to @command{gawk} versions prior to 4.0 were removed. +Of significant note for that edition was @ref{Debugger}. For FSF edition @ifclear FOR_PRINT @@ -1914,8 +1971,7 @@ the content has been reorganized into parts, and the major new additions are @ref{Arbitrary Precision Arithmetic}, and @ref{Dynamic Extensions}. -This @value{DOCUMENT} will undoubtedly continue to evolve. An electronic -version comes with the @command{gawk} distribution from the FSF. If you +This @value{DOCUMENT} will undoubtedly continue to evolve. If you find an error in this @value{DOCUMENT}, please report it! @xref{Bugs}, for information on submitting problem reports electronically. @@ -1924,7 +1980,7 @@ for information on submitting problem reports electronically. @unnumberedsec How to Stay Current It may be you have a version of @command{gawk} which is newer than the -one described in this @value{DOCUMENT}. To find out what has changed, +one described here. To find out what has changed, you should first look at the @file{NEWS} file in the @command{gawk} distribution, which provides a high level summary of what changed in each release. @@ -1959,8 +2015,10 @@ a @command{gawk} extension that you would like to share with the rest of the world, please see @uref{http://awk.info/?contribute} for how to contribute it to the web site. +@ignore As of this writing, this website is in search of a maintainer; please contact me if you are interested. +@end ignore @ignore Other links: @@ -2096,15 +2154,24 @@ Andrew Schorr, Corinna Vinschen, and Eli Zaretskii (in alphabetical order) -make up the current -@command{gawk} ``crack portability team.'' Without their hard work and -help, @command{gawk} would not be nearly the fine program it is today. It -has been and continues to be a pleasure working with this team of fine -people. +make up the current @command{gawk} ``crack portability team.'' Without +their hard work and help, @command{gawk} would not be nearly the robust, +portable program it is today. It has been and continues to be a pleasure +working with this team of fine people. Notable code and documentation contributions were made by a number of people. @xref{Contributors}, for the full list. +@ifset FOR_PRINT +@cindex Oram, Andy +Thanks to Andy Oram, of O'Reilly Media, for initiating +the fourth edition and for his support during the work. +@end ifset + +Thanks to Michael Brennan for the Foreword. + +@cindex Duman, Patrice +@cindex Berry, Karl Thanks to Patrice Dumas for the new @command{makeinfo} program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. @@ -2146,7 +2213,7 @@ take advantage of those opportunities. Arnold Robbins @* Nof Ayalon @* ISRAEL @* -May, 2014 +December, 2014 @end iftex @ifnotinfo @@ -2365,7 +2432,7 @@ to keep you from worrying about the complexities of computer programming: @example -$ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} +$ @kbd{awk 'BEGIN @{ print "Don\47t Panic!" @}'} @print{} Don't Panic! @end example @@ -2373,11 +2440,11 @@ $ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} reading any input. If there are no other statements in your program, as is the case here, @command{awk} just stops, instead of trying to read input it doesn't know how to process. -The @samp{\47} is a magic way of getting a single quote into +The @samp{\47} is a magic way (explained later) of getting a single quote into the program, without having to engage in ugly shell quoting tricks. @quotation NOTE -As a side note, if you use Bash as your shell, you should execute the +If you use Bash as your shell, you should execute the command @samp{set +H} before running this program interactively, to disable the C shell-style command history, which treats @samp{!} as a special character. We recommend putting this command into your personal @@ -2407,7 +2474,7 @@ $ @kbd{awk '@{ print @}'} @cindex @command{awk} programs, running @cindex @command{awk} programs, lengthy @cindex files, @command{awk} programs in -Sometimes your @command{awk} programs can be very long. In this case, it is +Sometimes @command{awk} programs are very long. In these cases, it is more convenient to put the program into a separate file. In order to tell @command{awk} to use that file for its program, you type: @@ -2437,7 +2504,7 @@ awk -f advice does the same thing as this one: @example -awk "BEGIN @{ print \"Don't Panic!\" @}" +awk 'BEGIN @{ print "Don\47t Panic!" @}' @end example @cindex quoting in @command{gawk} command lines @@ -2449,6 +2516,8 @@ specify with @option{-f}, because most @value{FN}s don't contain any of the shel special characters. Notice that in @file{advice}, the @command{awk} program did not have single quotes around it. The quotes are only needed for programs that are provided on the @command{awk} command line. +(Also, placing the program in a file allows us to use a literal single quote in the program +text, instead of the magic @samp{\47}.) @c STARTOFRANGE sq1x @cindex single quote (@code{'}) in @command{gawk} command lines @@ -2512,7 +2581,7 @@ written in @command{awk}. according to the instructions in your program. (This is different from a @dfn{compiled} language such as C, where your program is first compiled into machine code that is executed directly by your system's -hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +processor.) The @command{awk} utility is thus termed an @dfn{interpreter}. Many modern languages are interperted. The line beginning with @samp{#!} lists the full @value{FN} of an @@ -2521,9 +2590,9 @@ to pass to that interpreter. The operating system then runs the interpreter with the given argument and the full argument list of the executed program. The first argument in the list is the full @value{FN} of the @command{awk} program. The rest of the argument list contains -either options to @command{awk}, or @value{DF}s, or both. Note that on +either options to @command{awk}, or @value{DF}s, or both. (Note that on many systems @command{awk} may be found in @file{/usr/bin} instead of -in @file{/bin}. Caveat Emptor. +in @file{/bin}.) Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2562,7 +2631,7 @@ to provide your script name. according to the instructions in your program. (This is different from a @dfn{compiled} language such as C, where your program is first compiled into machine code that is executed directly by your system's -hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +processor.) The @command{awk} utility is thus termed an @dfn{interpreter}. Many modern languages are interperted. The line beginning with @samp{#!} lists the full @value{FN} of an @@ -2571,9 +2640,9 @@ to pass to that interpreter. The operating system then runs the interpreter with the given argument and the full argument list of the executed program. The first argument in the list is the full @value{FN} of the @command{awk} program. The rest of the argument list contains -either options to @command{awk}, or @value{DF}s, or both. Note that on +either options to @command{awk}, or @value{DF}s, or both. (Note that on many systems @command{awk} may be found in @file{/usr/bin} instead of -in @file{/bin}. Caveat Emptor. +in @file{/bin}.) Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2752,8 +2821,14 @@ Thus, the example seen @ifnotinfo previously @end ifnotinfo -in @ref{Read Terminal}, -is applicable: +in @ref{Read Terminal}: + +@example +awk 'BEGIN @{ print "Don\47t Panic!" @}' +@end example + +@noindent +could instead be written this way: @example $ @kbd{awk "BEGIN @{ print \"Don't Panic!\" @}"} @@ -2783,7 +2858,7 @@ awk -F"" '@var{program}' @var{files} # wrong! @end example @noindent -In the second case, @command{awk} will attempt to use the text of the program +In the second case, @command{awk} attempts to use the text of the program as the value of @code{FS}, and the first @value{FN} as the text of the program! This results in syntax errors at best, and confusing behavior at worst. @end itemize @@ -2848,6 +2923,9 @@ $ awk -v sq="'" 'BEGIN @{ print "Here is a single quote <" sq ">" @}' @print{} Here is a single quote <'> @end example +(Here, the two string constants and the value of @code{sq} are concatenated +into a single string which is printed by @code{print}.) + If you really need both single and double quotes in your @command{awk} program, it is probably best to move it into a separate file, where the shell won't be part of the picture, and you can say what you mean. @@ -2911,7 +2989,7 @@ The second @value{DF}, called @file{inventory-shipped}, contains information about monthly shipments. In both files, each line is considered to be one @dfn{record}. -In the @value{DF} @file{mail-list}, each record contains the name of a person, +In @file{mail-list}, each record contains the name of a person, his/her phone number, his/her email-address, and a code for their relationship with the author of the list. The columns are aligned using spaces. @@ -3071,7 +3149,7 @@ Print the length of the longest line in @file{data}: @example expand data | awk '@{ if (x < length($0)) x = length($0) @} - END @{ print "maximum line length is " x @}' + END @{ print "maximum line length is " x @}' @end example This example differs slightly from the previous one: @@ -3103,7 +3181,7 @@ Print the total number of bytes used by @var{files}: @example ls -l @var{files} | awk '@{ x += $5 @} - END @{ print "total bytes: " x @}' + END @{ print "total bytes: " x @}' @end example @item @@ -3147,7 +3225,7 @@ the program would print the odd-numbered lines. @cindex @command{awk} programs The @command{awk} utility reads the input files one line at a -time. For each line, @command{awk} tries the patterns of each of the rules. +time. For each line, @command{awk} tries the patterns of each rule. If several patterns match, then several actions execute in the order in which they appear in the @command{awk} program. If no patterns match, then no actions run. @@ -3155,7 +3233,7 @@ no actions run. After processing all the rules that match the line (and perhaps there are none), @command{awk} reads the next line. (However, @pxref{Next Statement}, -and also @pxref{Nextfile Statement}). +and also @pxref{Nextfile Statement}.) This continues until the program reaches the end of the file. For example, the following @command{awk} program contains two rules: @@ -3229,13 +3307,12 @@ the file was last modified. Its output looks like this: @noindent @cindex line continuations, with C shell The first field contains read-write permissions, the second field contains -the number of links to the file, and the third field identifies the owner of -the file. The fourth field identifies the group of the file. -The fifth field contains the size of the file in bytes. The +the number of links to the file, and the third field identifies the file's owner. +The fourth field identifies the file's group. +The fifth field contains the file's size in bytes. The sixth, seventh, and eighth fields contain the month, day, and time, respectively, that the file was last modified. Finally, the ninth field -contains the @value{FN}.@footnote{The @samp{LC_ALL=C} is -needed to produce this traditional-style output from @command{ls}.} +contains the @value{FN}. @c @cindex automatic initialization @cindex initialization, automatic @@ -3639,13 +3716,13 @@ The @option{-v} option can only set one variable, but it can be used more than once, setting another variable each time, like this: @samp{awk @w{-v foo=1} @w{-v bar=2} @dots{}}. -@cindex built-in variables, @code{-v} option@comma{} setting with -@cindex variables, built-in, @code{-v} option@comma{} setting with +@cindex predefined variables, @code{-v} option@comma{} setting with +@cindex variables, predefined @code{-v} option@comma{} setting with @quotation CAUTION Using @option{-v} to set the values of the built-in variables may lead to surprising results. @command{awk} will reset the values of those variables as it needs to, possibly ignoring any -predefined value you may have given. +initial value you may have given. @end quotation @item -W @var{gawk-opt} @@ -3728,7 +3805,7 @@ Print the short version of the General Public License and then exit. @cindex variables, global, printing list of Print a sorted list of global variables, their types, and final values to @var{file}. If no @var{file} is provided, print this -list to the file named @file{awkvars.out} in the current directory. +list to a file named @file{awkvars.out} in the current directory. No space is allowed between the @option{-d} and @var{file}, if @var{file} is supplied. @@ -3748,7 +3825,8 @@ names like @code{i}, @code{j}, etc.) @cindex @command{awk} debugging, enabling Enable debugging of @command{awk} programs (@pxref{Debugging}). -By default, the debugger reads commands interactively from the keyboard. +By default, the debugger reads commands interactively from the keyboard +(standard input). The optional @var{file} argument allows you to specify a file with a list of commands for the debugger to execute non-interactively. No space is allowed between the @option{-D} and @var{file}, if @@ -3824,7 +3902,7 @@ that @command{gawk} accepts and then exit. @cindex @option{-i} option @cindex @option{--include} option @cindex @command{awk} programs, location of -Read @command{awk} source library from @var{source-file}. This option +Read an @command{awk} source library from @var{source-file}. This option is completely equivalent to using the @code{@@include} directive inside your program. This option is very similar to the @option{-f} option, but there are two important differences. First, when @option{-i} is @@ -3848,7 +3926,7 @@ environment variable. The correct library suffix for your platform will be supplied by default, so it need not be specified in the extension name. The extension initialization routine should be named @code{dl_load()}. An alternative is to use the @code{@@load} keyword inside the program to load -a shared library. This feature is described in detail in @ref{Dynamic Extensions}. +a shared library. This advanced feature is described in detail in @ref{Dynamic Extensions}. @item @option{-L}[@var{value}] @itemx @option{--lint}[@code{=}@var{value}] @@ -3897,6 +3975,8 @@ values in input data @quotation CAUTION This option can severely break old programs. Use with care. + +This option may disappear in a future version of @command{gawk}. @end quotation @item @option{-N} @@ -4060,6 +4140,7 @@ if they had been concatenated together into one big file. This is useful for creating libraries of @command{awk} functions. These functions can be written once and then retrieved from a standard place, instead of having to be included into each individual program. +The @option{-i} option is similar in this regard. (As mentioned in @ref{Definition Syntax}, function names must be unique.) @@ -4133,15 +4214,18 @@ Any additional arguments on the command line are normally treated as input files to be processed in the order specified. However, an argument that has the form @code{@var{var}=@var{value}}, assigns the value @var{value} to the variable @var{var}---it does not specify a -file at all. -(See -@ref{Assignment Options}.) +file at all. (See @ref{Assignment Options}.) In the following example, +@var{count=1} is a variable assignment, not a @value{FN}: + +@example +awk -f program.awk file1 count=1 file2 +@end example @cindex @command{gawk}, @code{ARGIND} variable in @cindex @code{ARGIND} variable, command-line arguments @cindex @code{ARGV} array, indexing into @cindex @code{ARGC}/@code{ARGV} variables, command-line arguments -All these arguments are made available to your @command{awk} program in the +All the command-line arguments are made available to your @command{awk} program in the @code{ARGV} array (@pxref{Built-in Variables}). Command-line options and the program text (if present) are omitted from @code{ARGV}. All other arguments, including variable assignments, are @@ -4251,72 +4335,80 @@ behaves. @cindex @env{AWKPATH} environment variable @cindex directories, searching for source files @cindex search paths, for source files -@cindex differences in @command{awk} and @command{gawk}, @code{AWKPATH} environment variable +@cindex differences in @command{awk} and @command{gawk}, @env{AWKPATH} environment variable @ifinfo The previous @value{SECTION} described how @command{awk} program files can be named on the command line with the @option{-f} option. @end ifinfo In most @command{awk} -implementations, you must supply a precise path name for each program +implementations, you must supply a precise pathname for each program file, unless the file is in the current directory. -But in @command{gawk}, if the @value{FN} supplied to the @option{-f} +But with @command{gawk}, if the @value{FN} supplied to the @option{-f} or @option{-i} options does not contain a directory separator @samp{/}, then @command{gawk} searches a list of directories (called the @dfn{search path}), one by one, looking for a file with the specified name. The search path is a string consisting of directory names -separated by colons@footnote{Semicolons on MS-Windows and MS-DOS.}. @command{gawk} gets its search path from the +separated by colons.@footnote{Semicolons on MS-Windows and MS-DOS.} +@command{gawk} gets its search path from the @env{AWKPATH} environment variable. If that variable does not exist, -@command{gawk} uses a default path, -@samp{.:/usr/local/share/awk}.@footnote{Your version of @command{gawk} -may use a different directory; it -will depend upon how @command{gawk} was built and installed. The actual -directory is the value of @samp{$(datadir)} generated when -@command{gawk} was configured. You probably don't need to worry about this, -though.} +or if it has an empty value, +@command{gawk} uses a default path (described shortly). The search path feature is particularly helpful for building libraries of useful @command{awk} functions. The library files can be placed in a standard directory in the default path and then specified on -the command line with a short @value{FN}. Otherwise, the full @value{FN} -would have to be typed for each file. +the command line with a short @value{FN}. Otherwise, you would have to +type the full @value{FN} for each file. -By using the @option{-i} option, or the @option{-e} and @option{-f} options, your command-line +By using the @option{-i} or @option{-f} options, your command-line @command{awk} programs can use facilities in @command{awk} library files (@pxref{Library Functions}). Path searching is not done if @command{gawk} is in compatibility mode. This is true for both @option{--traditional} and @option{--posix}. @xref{Options}. -If the source code is not found after the initial search, the path is searched -again after adding the default @samp{.awk} suffix to the @value{FN}. +If the source code file is not found after the initial search, the path is searched +again after adding the suffix @samp{.awk} to the @value{FN}. -@quotation NOTE -@c 4/2014: -@c using @samp{.} to get quotes, since @file{} no longer supplies them. -To include -the current directory in the path, either place -@samp{.} explicitly in the path or write a null entry in the -path. (A null entry is indicated by starting or ending the path with a -colon or by placing two colons next to each other [@samp{::}].) -This path search mechanism is similar +@command{gawk}'s path search mechanism is similar to the shell's. (See @uref{http://www.gnu.org/software/bash/manual/, -@cite{The Bourne-Again SHell manual}.}) +@cite{The Bourne-Again SHell manual}}.) +It treats a null entry in the path as indicating the current +directory. +(A null entry is indicated by starting or ending the path with a +colon or by placing two colons next to each other [@samp{::}].) -However, @command{gawk} always looks in the current directory @emph{before} -searching @env{AWKPATH}, so there is no real reason to include -the current directory in the search path. -@c Prior to 4.0, gawk searched the current directory after the -@c path search, but it's not worth documenting it. +@quotation NOTE +To include the current directory in the path, either place @file{.} +as an entry in the path or write a null entry in the path. + +Different past versions of @command{gawk} would also look explicitly in +the current directory, either before or after the path search. As of +@value{PVERSION} 4.1.2, this no longer happens, and if you wish to look +in the current directory, you must include @file{.} either as a separate +entry, or as a null entry in the search path. @end quotation -If @env{AWKPATH} is not defined in the -environment, @command{gawk} places its default search path into -@code{ENVIRON["AWKPATH"]}. This makes it easy to determine -the actual search path that @command{gawk} used -from within an @command{awk} program. +The default value for @env{AWKPATH} is +@samp{.:/usr/local/share/awk}.@footnote{Your version of @command{gawk} +may use a different directory; it +will depend upon how @command{gawk} was built and installed. The actual +directory is the value of @code{$(datadir)} generated when +@command{gawk} was configured. You probably don't need to worry about this, +though.} Since @file{.} is included at the beginning, @command{gawk} +searches first in the current directory and then in @file{/usr/local/share/awk}. +In practice, this means that you will rarely need to change the +value of @env{AWKPATH}. + +@xref{Shell Startup Files}, for information on functions that help to +manipulate the @env{AWKPATH} variable. + +@command{gawk} places the value of the search path that it used into +@code{ENVIRON["AWKPATH"]}. This provides access to the actual search +path value from within an @command{awk} program. While you can change @code{ENVIRON["AWKPATH"]} within your @command{awk} program, this has no effect on the running program's behavior. This makes @@ -4340,6 +4432,18 @@ the platform. For example, on GNU/Linux systems, the suffix @samp{.so} is used. The search path specified is also used for extensions loaded via the @code{@@load} keyword (@pxref{Loading Shared Libraries}). +If @env{AWKLIBPATH} does not exist in the environment, or if it has +an empty value, @command{gawk} uses a default path; this +is typically @samp{/usr/local/lib/gawk}, although it can vary depending +upon how @command{gawk} was built. + +@xref{Shell Startup Files}, for information on functions that help to +manipulate the @env{AWKLIBPATH} variable. + +@command{gawk} places the value of the search path that it used into +@code{ENVIRON["AWKLIBPATH"]}. This provides access to the actual search +path value from within an @command{awk} program. + @node Other Environment Variables @subsection Other Environment Variables @@ -4348,16 +4452,6 @@ behavior, but they are more specialized. Those in the following list are meant to be used by regular users. @table @env -@item POSIXLY_CORRECT -Causes @command{gawk} to switch to POSIX compatibility -mode, disabling all traditional and GNU extensions. -@xref{Options}. - -@item GAWK_SOCK_RETRIES -Controls the number of times @command{gawk} attempts to -retry a two-way TCP/IP (socket) connection before giving up. -@xref{TCP/IP Networking}. - @item GAWK_MSEC_SLEEP Specifies the interval between connection retries, in milliseconds. On systems that do not support @@ -4368,6 +4462,16 @@ the value is rounded up to an integral number of seconds. Specifies the time, in milliseconds, for @command{gawk} to wait for input before returning with an error. @xref{Read Timeout}. + +@item GAWK_SOCK_RETRIES +Controls the number of times @command{gawk} attempts to +retry a two-way TCP/IP (socket) connection before giving up. +@xref{TCP/IP Networking}. + +@item POSIXLY_CORRECT +Causes @command{gawk} to switch to POSIX compatibility +mode, disabling all traditional and GNU extensions. +@xref{Options}. @end table The environment variables in the following list are meant @@ -4382,7 +4486,7 @@ file as the size of the memory buffer to allocate for I/O. Otherwise, the value should be a number, and @command{gawk} uses that number as the size of the buffer to allocate. (When this variable is not set, @command{gawk} uses the smaller of the file's size and the ``default'' -blocksize, which is usually the filesystems I/O blocksize.) +blocksize, which is usually the filesystem's I/O blocksize.) @item AWK_HASH If this variable exists with a value of @samp{gst}, @command{gawk} @@ -4397,10 +4501,11 @@ for debugging problems on filesystems on non-POSIX operating systems where I/O is performed in records, not in blocks. @item GAWK_MSG_SRC -If this variable exists, @command{gawk} includes the source file -name and line number from which warning and/or fatal messages +If this variable exists, @command{gawk} includes the file +name and line number within the @command{gawk} source code +from which warning and/or fatal messages are generated. Its purpose is to help isolate the source of a -message, since there can be multiple places which produce the +message, since there are multiple places which produce the same warning or error message. @item GAWK_NO_DFA @@ -4416,11 +4521,11 @@ This specifies the amount by which @command{gawk} should grow its internal evaluation stack, when needed. @item INT_CHAIN_MAX -The average number of items @command{gawk} will maintain on a +The intended maximum number of items @command{gawk} will maintain on a hash chain for managing arrays indexed by integers. @item STR_CHAIN_MAX -The average number of items @command{gawk} will maintain on a +The intended maximum number of items @command{gawk} will maintain on a hash chain for managing arrays indexed by strings. @item TIDYMEM @@ -4493,8 +4598,8 @@ produces the following result: @example $ @kbd{gawk -f test2} -@print{} This is file test1. -@print{} This is file test2. +@print{} This is script test1. +@print{} This is script test2. @end example @code{gawk} runs the @file{test2} script which includes @file{test1} @@ -4524,9 +4629,9 @@ following results: @example $ @kbd{gawk -f test3} -@print{} This is file test1. -@print{} This is file test2. -@print{} This is file test3. +@print{} This is script test1. +@print{} This is script test2. +@print{} This is script test3. @end example The @value{FN} can, of course, be a pathname. For example: @@ -4543,9 +4648,9 @@ or: @end example @noindent -are valid. The @code{AWKPATH} environment variable can be of great +are valid. The @env{AWKPATH} environment variable can be of great value when using @code{@@include}. The same rules for the use -of the @code{AWKPATH} variable in command-line file searches +of the @env{AWKPATH} variable in command-line file searches (@pxref{AWKPATH Variable}) apply to @code{@@include} also. @@ -4553,7 +4658,7 @@ This is very helpful in constructing @command{gawk} function libraries. If you have a large script with useful, general purpose @command{awk} functions, you can break it down into library files and put those files in a special directory. You can then include those ``libraries,'' using -either the full pathnames of the files, or by setting the @code{AWKPATH} +either the full pathnames of the files, or by setting the @env{AWKPATH} environment variable accordingly and then using @code{@@include} with just the file part of the full pathname. Of course you can have more than one directory to keep library files; the more complex the working @@ -4613,6 +4718,7 @@ that requires access to an extension. @ref{Dynamic Extensions}, describes how to write extensions (in C or C++) that can be loaded with either @code{@@load} or the @option{-l} option. +It also describes the @code{ordchr} extension. @node Obsolete @section Obsolete Options and/or Features @@ -4681,15 +4787,15 @@ awk '@{ sum += $1 @} END @{ print sum @}' @end example @command{gawk} actually supports this but it is purposely undocumented -because it is considered bad style. The correct way to write such a program -is either +because it is bad style. The correct way to write such a program +is either: @example awk '@{ sum += $1 @} ; END @{ print sum @}' @end example @noindent -or +or: @example awk '@{ sum += $1 @} @@ -4697,8 +4803,7 @@ awk '@{ sum += $1 @} @end example @noindent -@xref{Statements/Lines}, for a fuller -explanation. +@xref{Statements/Lines}, for a fuller explanation. You can insert newlines after the @samp{;} in @code{for} loops. This seems to have been a long-undocumented feature in Unix @command{awk}. @@ -4738,7 +4843,8 @@ affects how @command{awk} processes input. @item You can use a single minus sign (@samp{-}) to refer to standard input -on the command line. +on the command line. @command{gawk} also lets you use the special +@value{FN} @file{/dev/stdin}. @item @command{gawk} pays attention to a number of environment variables. @@ -4927,7 +5033,7 @@ such as TAB or newline. While there is nothing to stop you from entering most unprintable characters directly in a string constant or regexp constant, they may look ugly. -The following table lists +The following list presents all the escape sequences used in @command{awk} and what they represent. Unless noted otherwise, all these escape sequences apply to both string constants and regexp constants: @@ -4993,6 +5099,7 @@ of hexadecimal digits (@samp{0}--@samp{9}, and either @samp{A}--@samp{F} or @samp{a}--@samp{f}). A maximum of two digts are allowed after the @samp{\x}. Any further hexadecimal digits are treated as simple letters or numbers. @value{COMMONEXT} +(The @samp{\x} escape sequence is not allowed in POSIX awk.) @quotation CAUTION In ISO C, the escape sequence continues until the first nonhexadecimal @@ -5001,7 +5108,10 @@ digit is seen. For many years, @command{gawk} would continue incorporating hexadecimal digits into the value until a non-hexadecimal digit or the end of the string was encountered. -However, using more than two hexadecimal digits produces +However, using more than two hexadecimal digits produced +undefined results. +As of @value{PVERSION} @strong{FIXME:} 4.3.0, only two digits +are processed. @end quotation @cindex @code{\} (backslash), @code{\/} escape sequence @@ -5043,13 +5153,13 @@ characters @samp{a+b}. @cindex @code{\} (backslash), in escape sequences @cindex portability For complete portability, do not use a backslash before any character not -shown in the previous list. +shown in the previous list and that is not an operator. To summarize: @itemize @value{BULLET} @item -The escape sequences in the table above are always processed first, +The escape sequences in the list above are always processed first, for both string constants and regexp constants. This happens very early, as soon as @command{awk} reads your program. @@ -5222,7 +5332,7 @@ are recognized and converted into corresponding real characters as the very first step in processing regexps. Here is a list of metacharacters. All characters that are not escape -sequences and that are not listed in the table stand for themselves: +sequences and that are not listed in the following stand for themselves: @c Use @asis so the docbook comes out ok. Sigh. @table @asis @@ -5279,10 +5389,10 @@ with @samp{A}. @cindex POSIX @command{awk}, period (@code{.})@comma{} using In strict POSIX mode (@pxref{Options}), -@samp{.} does not match the @value{NUL} +@samp{.} does not match the @sc{nul} character, which is a character with all bits equal to zero. -Otherwise, @value{NUL} is just another character. Other versions of @command{awk} -may not be able to match the @value{NUL} character. +Otherwise, @sc{nul} is just another character. Other versions of @command{awk} +may not be able to match the @sc{nul} character. @cindex @code{[]} (square brackets), regexp operator @cindex square brackets (@code{[]}), regexp operator @@ -5347,7 +5457,7 @@ component (e.g., in @samp{ph*}, it applies just to the @samp{h}). To cause @samp{*} to apply to a larger sub-expression, use parentheses: @samp{(ph)*} matches @samp{ph}, @samp{phph}, @samp{phphph} and so on. -Second, @samp{*} finds as many repetititons as possible. If the text +Second, @samp{*} finds as many repetitions as possible. If the text to be matched is @samp{phhhhhhhhhhhhhhooey}, @samp{ph*} matches all of the @samp{h}s. @@ -5479,7 +5589,7 @@ characters to be matched. @cindex Extended Regular Expressions (EREs) @cindex EREs (Extended Regular Expressions) @cindex @command{egrep} utility -This treatment of @samp{\} in bracket expressions +The treatment of @samp{\} in bracket expressions is compatible with other @command{awk} implementations and is also mandated by POSIX. The regular expressions in @command{awk} are a superset @@ -5596,11 +5706,11 @@ Consider the following: echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' @end example -This example uses the @code{sub()} function (which we haven't discussed yet; -@pxref{String Functions}) -to make a change to the input record. Here, the regexp @code{/a+/} -indicates ``one or more @samp{a} characters,'' and the replacement -text is @samp{<A>}. +This example uses the @code{sub()} function to make a change to the input +record. (@code{sub()} replaces the first instance of any text matched +by the first argument with the string provided as the second argument; +@pxref{String Functions}). Here, the regexp @code{/a+/} indicates ``one +or more @samp{a} characters,'' and the replacement text is @samp{<A>}. The input contains four @samp{a} characters. @command{awk} (and POSIX) regular expressions always match @@ -5716,7 +5826,7 @@ intend a regexp match. @cindex regular expressions, dynamic, with embedded newlines @cindex newlines, in dynamic regexps -Some versions of @command{awk} do not allow the newline +Some older versions of @command{awk} do not allow the newline character to be used inside a bracket expression for a dynamic regexp: @example @@ -5725,7 +5835,7 @@ $ @kbd{awk '$0 ~ "[ \t\n]"'} @error{} ]... @error{} source line number 1 @error{} context is -@error{} >>> <<< +@error{} $0 ~ "[ >>> \t\n]" <<< @end example @cindex newlines, in regexp constants @@ -5754,7 +5864,7 @@ occur often in practice, but it's worth noting for future reference. @cindex regular expressions, dynamic, with embedded newlines @cindex newlines, in dynamic regexps -Some versions of @command{awk} do not allow the newline +Some older versions of @command{awk} do not allow the newline character to be used inside a bracket expression for a dynamic regexp: @example @@ -5763,7 +5873,7 @@ $ @kbd{awk '$0 ~ "[ \t\n]"'} @error{} ]... @error{} source line number 1 @error{} context is -@error{} >>> <<< +@error{} $0 ~ "[ >>> \t\n]" <<< @end example @cindex newlines, in regexp constants @@ -5946,7 +6056,7 @@ are allowed. Traditional Unix @command{awk} regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (@samp{[[:alnum:]]}, etc.) are supported, -as BWK @command{awk} does support them. +as BWK @command{awk} supports them. Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. @@ -6087,11 +6197,6 @@ Within bracket expressions, POSIX character classes let you specify certain groups of characters in a locale-independent fashion. @item -@command{gawk}'s @code{IGNORECASE} variable lets you control the -case sensitivity of regexp matching. In other @command{awk} -versions, use @code{tolower()} or @code{toupper()}. - -@item Regular expressions match the leftmost longest text in the string being matched. This matters for cases where you need to know the extent of the match, such as for text substitution and when the record separator @@ -6101,6 +6206,11 @@ is a regexp. Matching expressions may use dynamic regexps, that is, string values treated as regular expressions. +@item +@command{gawk}'s @code{IGNORECASE} variable lets you control the +case sensitivity of regexp matching. In other @command{awk} +versions, use @code{tolower()} or @code{toupper()}. + @end itemize @c ENDOFRANGE regexp @@ -6119,7 +6229,7 @@ standard input (by default, this is the keyboard, but often it is a pipe from an command) or from files whose names you specify on the @command{awk} command line. If you specify input files, @command{awk} reads them in order, processing all the data from one before going on to the next. -The name of the current input file can be found in the built-in variable +The name of the current input file can be found in the predefined variable @code{FILENAME} (@pxref{Built-in Variables}). @@ -6167,9 +6277,9 @@ used with it do not have to be named on the @command{awk} command line @cindex @code{FNR} variable @command{awk} divides the input for your program into records and fields. It keeps track of the number of records that have been read so far from -the current input file. This value is stored in a built-in variable -called @code{FNR} which is reset to zero when a new file is started. -Another built-in variable, @code{NR}, records the total number of input +the current input file. This value is stored in a predefined variable +called @code{FNR} which is reset to zero every time a new file is started. +Another predefined variable, @code{NR}, records the total number of input records read so far from all @value{DF}s. It starts at zero, but is never automatically reset to zero. @@ -6187,7 +6297,7 @@ Records are separated by a character called the @dfn{record separator}. By default, the record separator is the newline character. This is why records are, by default, single lines. A different character can be used for the record separator by -assigning the character to the built-in variable @code{RS}. +assigning the character to the predefined variable @code{RS}. @cindex newlines, as record separators @cindex @code{RS} variable @@ -6298,7 +6408,8 @@ Using an unusual character such as @samp{/} is more likely to produce correct behavior in the majority of cases, but there are no guarantees. The moral is: Know Your Data. -There is one unusual case, that occurs when @command{gawk} is +When using regular characters as the record separator, +there is one unusual case that occurs when @command{gawk} is being fully POSIX-compliant (@pxref{Options}). Then, the following (extreme) pipeline prints a surprising @samp{1}: @@ -6387,7 +6498,7 @@ $ @kbd{echo record 1 AAAA record 2 BBBB record 3 |} @noindent The square brackets delineate the contents of @code{RT}, letting you -see the leading and trailing whitespace. The final value of @code{RT} +see the leading and trailing whitespace. The final value of @code{RT} is a newline. @xref{Simple Sed}, for a more useful example of @code{RS} as a regexp and @code{RT}. @@ -6406,7 +6517,7 @@ metacharacters match the beginning and end of a @emph{string}, and not the beginning and end of a @emph{line}. As a result, something like @samp{RS = "^[[:upper:]]"} can only match at the beginning of a file. This is because @command{gawk} views the input file as one long string -that happens to contain newline characters in it. +that happens to contain newline characters. It is thus best to avoid anchor characters in the value of @code{RS}. @end quotation @@ -6416,7 +6527,7 @@ variable are @command{gawk} extensions; they are not available in compatibility mode (@pxref{Options}). In compatibility mode, only the first character of the value of -@code{RS} is used to determine the end of the record. +@code{RS} determines the end of the record. @cindex sidebar, @code{RS = "\0"} Is Not Portable @ifdocbook @@ -6431,7 +6542,7 @@ a value that you know doesn't occur in the input file. This is hard to do in a general way, such that a program always works for arbitrary input files. -You might think that for text files, the @value{NUL} character, which +You might think that for text files, the @sc{nul} character, which consists of a character with all bits equal to zero, is a good value to use for @code{RS} in this case: @@ -6440,27 +6551,28 @@ BEGIN @{ RS = "\0" @} # whole file becomes one record? @end example @cindex differences in @command{awk} and @command{gawk}, strings, storing -@command{gawk} in fact accepts this, and uses the @value{NUL} +@command{gawk} in fact accepts this, and uses the @sc{nul} character for the record separator. This works for certain special files, such as @file{/proc/environ} on -GNU/Linux systems, where the @value{NUL} character is in fact the record separator. +GNU/Linux systems, where the @sc{nul} character is in fact the record separator. However, this usage is @emph{not} portable to most other @command{awk} implementations. @cindex dark corner, strings, storing Almost all other @command{awk} implementations@footnote{At least that we know about.} store strings internally as C-style strings. C strings use the -@value{NUL} character as the string terminator. In effect, this means that +@sc{nul} character as the string terminator. In effect, this means that @samp{RS = "\0"} is the same as @samp{RS = ""}. @value{DARKCORNER} -It happens that recent versions of @command{mawk} can use the @value{NUL} +It happens that recent versions of @command{mawk} can use the @sc{nul} character as a record separator. However, this is a special case: -@command{mawk} does not allow embedded @value{NUL} characters in strings. +@command{mawk} does not allow embedded @sc{nul} characters in strings. +(This may change in a future version of @command{mawk}.) @cindex records, treating files as @cindex treating files, as single records -@xref{Readfile Function}, for an interesting, portable way to read +@xref{Readfile Function}, for an interesting way to read whole files. If you are using @command{gawk}, see @ref{Extension Sample Readfile}, for another option. @@ -6481,7 +6593,7 @@ a value that you know doesn't occur in the input file. This is hard to do in a general way, such that a program always works for arbitrary input files. -You might think that for text files, the @value{NUL} character, which +You might think that for text files, the @sc{nul} character, which consists of a character with all bits equal to zero, is a good value to use for @code{RS} in this case: @@ -6490,27 +6602,28 @@ BEGIN @{ RS = "\0" @} # whole file becomes one record? @end example @cindex differences in @command{awk} and @command{gawk}, strings, storing -@command{gawk} in fact accepts this, and uses the @value{NUL} +@command{gawk} in fact accepts this, and uses the @sc{nul} character for the record separator. This works for certain special files, such as @file{/proc/environ} on -GNU/Linux systems, where the @value{NUL} character is in fact the record separator. +GNU/Linux systems, where the @sc{nul} character is in fact the record separator. However, this usage is @emph{not} portable to most other @command{awk} implementations. @cindex dark corner, strings, storing Almost all other @command{awk} implementations@footnote{At least that we know about.} store strings internally as C-style strings. C strings use the -@value{NUL} character as the string terminator. In effect, this means that +@sc{nul} character as the string terminator. In effect, this means that @samp{RS = "\0"} is the same as @samp{RS = ""}. @value{DARKCORNER} -It happens that recent versions of @command{mawk} can use the @value{NUL} +It happens that recent versions of @command{mawk} can use the @sc{nul} character as a record separator. However, this is a special case: -@command{mawk} does not allow embedded @value{NUL} characters in strings. +@command{mawk} does not allow embedded @sc{nul} characters in strings. +(This may change in a future version of @command{mawk}.) @cindex records, treating files as @cindex treating files, as single records -@xref{Readfile Function}, for an interesting, portable way to read +@xref{Readfile Function}, for an interesting way to read whole files. If you are using @command{gawk}, see @ref{Extension Sample Readfile}, for another option. @end cartouche @@ -6570,7 +6683,7 @@ field. @cindex @code{NF} variable @cindex fields, number of -@code{NF} is a built-in variable whose value is the number of fields +@code{NF} is a predefined variable whose value is the number of fields in the current record. @command{awk} automatically updates the value of @code{NF} each time it reads a record. No matter how many fields there are, the last field in a record can be represented by @code{$NF}. @@ -6592,15 +6705,11 @@ $ @kbd{awk '$1 ~ /li/ @{ print $0 @}' mail-list} @noindent This example prints each record in the file @file{mail-list} whose first -field contains the string @samp{li}. The operator @samp{~} is called a -@dfn{matching operator} -(@pxref{Regexp Usage}); -it tests whether a string (here, the field @code{$1}) matches a given regular -expression. +field contains the string @samp{li}. -By contrast, the following example -looks for @samp{li} in @emph{the entire record} and prints the first -field and the last field for each matching input record: +By contrast, the following example looks for @samp{li} in @emph{the +entire record} and prints the first and last fields for each matching +input record: @example $ @kbd{awk '/li/ @{ print $1, $NF @}' mail-list} @@ -6663,7 +6772,7 @@ implementations may behave differently.) As mentioned in @ref{Fields}, @command{awk} stores the current record's number of fields in the built-in -variable @code{NF} (also @pxref{Built-in Variables}). The expression +variable @code{NF} (also @pxref{Built-in Variables}). Thus, the expression @code{$NF} is not a special feature---it is the direct consequence of evaluating @code{NF} and using its value as a field number. @@ -6723,8 +6832,8 @@ It is also possible to also assign contents to fields that are out of range. For example: @example -$ awk '@{ $6 = ($5 + $4 + $3 + $2) -> print $6 @}' inventory-shipped +$ @kbd{awk '@{ $6 = ($5 + $4 + $3 + $2)} +> @kbd{ print $6 @}' inventory-shipped} @print{} 168 @print{} 297 @print{} 301 @@ -6813,7 +6922,7 @@ Here is an example: @example $ echo a b c d e f | awk '@{ print "NF =", NF; -> NF = 3; print $0 @}' +> NF = 3; print $0 @}' @print{} NF = 6 @print{} a b c @end example @@ -6821,7 +6930,7 @@ $ echo a b c d e f | awk '@{ print "NF =", NF; @cindex portability, @code{NF} variable@comma{} decrementing @quotation CAUTION Some versions of @command{awk} don't -rebuild @code{$0} when @code{NF} is decremented. Caveat emptor. +rebuild @code{$0} when @code{NF} is decremented. @end quotation Finally, there are times when it is convenient to force @@ -6857,7 +6966,7 @@ record, exactly as it was read from the input. This includes any leading or trailing whitespace, and the exact whitespace (or other characters) that separate the fields. -It is a not-uncommon error to try to change the field separators +It is a common error to try to change the field separators in a record simply by setting @code{FS} and @code{OFS}, and then expecting a plain @samp{print} or @samp{print $0} to print the modified record. @@ -6882,7 +6991,7 @@ record, exactly as it was read from the input. This includes any leading or trailing whitespace, and the exact whitespace (or other characters) that separate the fields. -It is a not-uncommon error to try to change the field separators +It is a common error to try to change the field separators in a record simply by setting @code{FS} and @code{OFS}, and then expecting a plain @samp{print} or @samp{print $0} to print the modified record. @@ -6932,7 +7041,7 @@ is split into three fields: @samp{m}, @samp{@bullet{}g}, and Note the leading spaces in the values of the second and third fields. @cindex troubleshooting, @command{awk} uses @code{FS} not @code{IFS} -The field separator is represented by the built-in variable @code{FS}. +The field separator is represented by the predefined variable @code{FS}. Shell programmers take note: @command{awk} does @emph{not} use the name @code{IFS} that is used by the POSIX-compliant shells (such as the Unix Bourne shell, @command{sh}, or Bash). @@ -7086,9 +7195,10 @@ $ @kbd{echo ' a b c d' | awk '@{ print; $2 = $2; print @}'} The first @code{print} statement prints the record as it was read, with leading whitespace intact. The assignment to @code{$2} rebuilds @code{$0} by concatenating @code{$1} through @code{$NF} together, -separated by the value of @code{OFS}. Because the leading whitespace -was ignored when finding @code{$1}, it is not part of the new @code{$0}. -Finally, the last @code{print} statement prints the new @code{$0}. +separated by the value of @code{OFS} (which is a space by default). +Because the leading whitespace was ignored when finding @code{$1}, +it is not part of the new @code{$0}. Finally, the last @code{print} +statement prints the new @code{$0}. @cindex @code{FS}, containing @code{^} @cindex @code{^} (caret), in @code{FS} @@ -7110,7 +7220,7 @@ also works this way. For example: @example $ @kbd{echo 'xxAA xxBxx C' |} > @kbd{gawk -F '(^x+)|( +)' '@{ for (i = 1; i <= NF; i++)} -> @kbd{printf "-->%s<--\n", $i @}'} +> @kbd{ printf "-->%s<--\n", $i @}'} @print{} --><-- @print{} -->AA<-- @print{} -->xxBxx<-- @@ -7173,15 +7283,10 @@ awk -F, '@var{program}' @var{input-files} @noindent sets @code{FS} to the @samp{,} character. Notice that the option uses an uppercase @samp{F} instead of a lowercase @samp{f}. The latter -option (@option{-f}) specifies a file -containing an @command{awk} program. Case is significant in command-line -options: -the @option{-F} and @option{-f} options have nothing to do with each other. -You can use both options at the same time to set the @code{FS} variable -@emph{and} get an @command{awk} program from a file. +option (@option{-f}) specifies a file containing an @command{awk} program. The value used for the argument to @option{-F} is processed in exactly the -same way as assignments to the built-in variable @code{FS}. +same way as assignments to the predefined variable @code{FS}. Any special characters in the field separator must be escaped appropriately. For example, to use a @samp{\} as the field separator on the command line, you would have to type: @@ -7292,7 +7397,7 @@ to @code{FS} (the backslash is stripped). This creates a regexp meaning If instead you want fields to be separated by a literal period followed by any single character, use @samp{FS = "\\.."}. -The following table summarizes how fields are split, based on the value +The following list summarizes how fields are split, based on the value of @code{FS} (@samp{==} means ``is equal to''): @table @code @@ -7313,8 +7418,7 @@ Leading and trailing matches of @var{regexp} delimit empty fields. @item FS == "" Each individual character in the record becomes a separate field. -(This is a @command{gawk} extension; it is not specified by the -POSIX standard.) +(This is a common extension; it is not specified by the POSIX standard.) @end table @cindex sidebar, Changing @code{FS} Does Not Affect the Fields @@ -7861,7 +7965,7 @@ BEGIN @{ RS = "" ; FS = "\n" @} Running the program produces the following output: @example -$ awk -f addrs.awk addresses +$ @kbd{awk -f addrs.awk addresses} @print{} Name is: Jane Doe @print{} Address is: 123 Main Street @print{} City and State are: Anywhere, SE 12345-6789 @@ -7873,12 +7977,9 @@ $ awk -f addrs.awk addresses @dots{} @end example -@xref{Labels Program}, for a more realistic -program that deals with address lists. -The following -table -summarizes how records are split, based on the -value of +@xref{Labels Program}, for a more realistic program that deals with +address lists. The following list summarizes how records are split, +based on the value of @ifinfo @code{RS}. (@samp{==} means ``is equal to.'') @@ -7913,8 +8014,8 @@ POSIX standard.) @cindex @command{gawk}, @code{RT} variable in @cindex @code{RT} variable -In all cases, @command{gawk} sets @code{RT} to the input text that matched the -value specified by @code{RS}. +If not in compatibility mode (@pxref{Options}), @command{gawk} sets +@code{RT} to the input text that matched the value specified by @code{RS}. But if the input file ended without any text that matches @code{RS}, then @command{gawk} sets @code{RT} to the null string. @c ENDOFRANGE recm @@ -8012,9 +8113,7 @@ processing on the next record @emph{right now}. For example: while (j == 0) @{ # get more text if (getline <= 0) @{ - m = "unexpected EOF or error" - m = (m ": " ERRNO) - print m > "/dev/stderr" + print("unexpected EOF or error:", ERRNO) > "/dev/stderr" exit @} # build up the line using string concatenation @@ -8173,7 +8272,7 @@ from the file @var{file}, and put it in the variable @var{var}. As above, @var{file} is a string-valued expression that specifies the file from which to read. -In this version of @code{getline}, none of the built-in variables are +In this version of @code{getline}, none of the predefined variables are changed and the record is not split into fields. The only variable changed is @var{var}.@footnote{This is not quite true. @code{RT} could be changed if @code{RS} is a regular expression.} @@ -8283,7 +8382,7 @@ bletch @end example @noindent -Notice that this program ran the command @command{who} and printed the previous result. +Notice that this program ran the command @command{who} and printed the result. (If you try this program yourself, you will of course get different results, depending upon who is logged in on your system.) @@ -8308,7 +8407,7 @@ Unfortunately, @command{gawk} has not been consistent in its treatment of a construct like @samp{@w{"echo "} "date" | getline}. Most versions, including the current version, treat it at as @samp{@w{("echo "} "date") | getline}. -(This how BWK @command{awk} behaves.) +(This is also how BWK @command{awk} behaves.) Some versions changed and treated it as @samp{@w{"echo "} ("date" | getline)}. (This is how @command{mawk} behaves.) @@ -8335,8 +8434,8 @@ BEGIN @{ @} @end example -In this version of @code{getline}, none of the built-in variables are -changed and the record is not split into fields. +In this version of @code{getline}, none of the predefined variables are +changed and the record is not split into fields. However, @code{RT} is set. @ifinfo @c Thanks to Paul Eggert for initial wording here @@ -8397,7 +8496,7 @@ When you use @samp{@var{command} |& getline @var{var}}, the output from the coprocess @var{command} is sent through a two-way pipe to @code{getline} and into the variable @var{var}. -In this version of @code{getline}, none of the built-in variables are +In this version of @code{getline}, none of the predefined variables are changed and the record is not split into fields. The only variable changed is @var{var}. However, @code{RT} is set. @@ -8444,7 +8543,7 @@ causes @command{awk} to set the value of @code{FILENAME}. Normally, @code{FILENAME} does not have a value inside @code{BEGIN} rules, because you have not yet started to process the command-line @value{DF}s. @value{DARKCORNER} -(@xref{BEGIN/END}, +(See @ref{BEGIN/END}; also @pxref{Auto-set}.) @item @@ -8491,7 +8590,7 @@ end of file is encountered, before the element in @code{a} is assigned? @command{gawk} treats @code{getline} like a function call, and evaluates the expression @samp{a[++c]} before attempting to read from @file{f}. However, some versions of @command{awk} only evaluate the expression once they -know that there is a string value to be assigned. Caveat Emptor. +know that there is a string value to be assigned. @end itemize @node Getline Summary @@ -8500,22 +8599,22 @@ know that there is a string value to be assigned. Caveat Emptor. @ref{table-getline-variants} summarizes the eight variants of @code{getline}, -listing which built-in variables are set by each one, +listing which predefined variables are set by each one, and whether the variant is standard or a @command{gawk} extension. -Note: for each variant, @command{gawk} sets the @code{RT} built-in variable. +Note: for each variant, @command{gawk} sets the @code{RT} predefined variable. @float Table,table-getline-variants @caption{@code{getline} Variants and What They Set} @multitable @columnfractions .33 .38 .27 -@headitem Variant @tab Effect @tab Standard / Extension -@item @code{getline} @tab Sets @code{$0}, @code{NF}, @code{FNR}, @code{NR}, and @code{RT} @tab Standard -@item @code{getline} @var{var} @tab Sets @var{var}, @code{FNR}, @code{NR}, and @code{RT} @tab Standard -@item @code{getline <} @var{file} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Standard -@item @code{getline @var{var} < @var{file}} @tab Sets @var{var} and @code{RT} @tab Standard -@item @var{command} @code{| getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Standard -@item @var{command} @code{| getline} @var{var} @tab Sets @var{var} and @code{RT} @tab Standard -@item @var{command} @code{|& getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Extension -@item @var{command} @code{|& getline} @var{var} @tab Sets @var{var} and @code{RT} @tab Extension +@headitem Variant @tab Effect @tab @command{awk} / @command{gawk} +@item @code{getline} @tab Sets @code{$0}, @code{NF}, @code{FNR}, @code{NR}, and @code{RT} @tab @command{awk} +@item @code{getline} @var{var} @tab Sets @var{var}, @code{FNR}, @code{NR}, and @code{RT} @tab @command{awk} +@item @code{getline <} @var{file} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{awk} +@item @code{getline @var{var} < @var{file}} @tab Sets @var{var} and @code{RT} @tab @command{awk} +@item @var{command} @code{| getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{awk} +@item @var{command} @code{| getline} @var{var} @tab Sets @var{var} and @code{RT} @tab @command{awk} +@item @var{command} @code{|& getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{gawk} +@item @var{command} @code{|& getline} @var{var} @tab Sets @var{var} and @code{RT} @tab @command{gawk} @end multitable @end float @c ENDOFRANGE getl @@ -8532,7 +8631,7 @@ This @value{SECTION} describes a feature that is specific to @command{gawk}. You may specify a timeout in milliseconds for reading input from the keyboard, a pipe, or two-way communication, including TCP/IP sockets. This can be done on a per input, command or connection basis, by setting a special element -in the @code{PROCINFO} (@pxref{Auto-set}) array: +in the @code{PROCINFO} array (@pxref{Auto-set}): @example PROCINFO["input_name", "READ_TIMEOUT"] = @var{timeout in milliseconds} @@ -8564,7 +8663,7 @@ while ((getline < "/dev/stdin") > 0) @command{gawk} terminates the read operation if input does not arrive after waiting for the timeout period, returns failure -and sets the @code{ERRNO} variable to an appropriate string value. +and sets @code{ERRNO} to an appropriate string value. A negative or zero value for the timeout is the same as specifying no timeout at all. @@ -8671,6 +8770,10 @@ The possibilities are as follows: @end multitable @item +@code{FNR} indicates how many records have been read from the current input file; +@code{NR} indicates how many records have been read in total. + +@item @command{gawk} sets @code{RT} to the text matched by @code{RS}. @item @@ -8681,7 +8784,7 @@ fields there are. The default way to split fields is between whitespace characters. @item -Fields may be referenced using a variable, as in @samp{$NF}. Fields +Fields may be referenced using a variable, as in @code{$NF}. Fields may also be assigned values, which causes the value of @code{$0} to be recomputed when it is later referenced. Assigning to a field with a number greater than @code{NF} creates the field and rebuilds the record, using @@ -8691,16 +8794,17 @@ thing. Decrementing @code{NF} throws away fields and rebuilds the record. @item Field splitting is more complicated than record splitting. -@multitable @columnfractions .40 .40 .20 +@multitable @columnfractions .40 .45 .15 @headitem Field separator value @tab Fields are split @dots{} @tab @command{awk} / @command{gawk} @item @code{FS == " "} @tab On runs of whitespace @tab @command{awk} @item @code{FS == @var{any single character}} @tab On that character @tab @command{awk} @item @code{FS == @var{regexp}} @tab On text matching the regexp @tab @command{awk} @item @code{FS == ""} @tab Each individual character is a separate field @tab @command{gawk} @item @code{FIELDWIDTHS == @var{list of columns}} @tab Based on character position @tab @command{gawk} -@item @code{FPAT == @var{regexp}} @tab On text around text matching the regexp @tab @command{gawk} +@item @code{FPAT == @var{regexp}} @tab On the text surrounding text matching the regexp @tab @command{gawk} @end multitable +@item Using @samp{FS = "\n"} causes the entire record to be a single field (assuming that newlines separate records). @@ -8709,11 +8813,11 @@ Using @samp{FS = "\n"} causes the entire record to be a single field This can also be done using command-line variable assignment. @item -@code{PROCINFO["FS"]} can be used to see how fields are being split. +Use @code{PROCINFO["FS"]} to see how fields are being split. @item Use @code{getline} in its various forms to read additional records, -from the default input stream, from a file, or from a pipe or co-process. +from the default input stream, from a file, or from a pipe or coprocess. @item Use @code{PROCINFO[@var{file}, "READ_TIMEOUT"]} to cause reads to timeout @@ -8782,6 +8886,7 @@ and discusses the @code{close()} built-in function. * Printf:: The @code{printf} statement. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in @command{gawk}. @command{gawk} allows access to inherited file descriptors. @@ -8793,7 +8898,7 @@ and discusses the @code{close()} built-in function. @node Print @section The @code{print} Statement -The @code{print} statement is used for producing output with simple, standardized +Use the @code{print} statement to produce output with simple, standardized formatting. You specify only the strings or numbers to print, in a list separated by commas. They are output, separated by single spaces, followed by a newline. The statement looks like this: @@ -8817,7 +8922,7 @@ expression. Numeric values are converted to strings and then printed. @cindex text, printing The simple statement @samp{print} with no items is equivalent to @samp{print $0}: it prints the entire current record. To print a blank -line, use @samp{print ""}, where @code{""} is the empty string. +line, use @samp{print ""}. To print a fixed piece of text, use a string constant, such as @w{@code{"Don't Panic"}}, as one item. If you forget to use the double-quote characters, your text is taken as an @command{awk} @@ -8825,8 +8930,8 @@ expression, and you will probably get an error. Keep in mind that a space is printed between any two items. Note that the @code{print} statement is a statement and not an -expression---you can't use it the pattern part of a pattern-action -statement, for example. +expression---you can't use it in the pattern part of a +@var{pattern}-@var{action} statement, for example. @node Print Examples @section @code{print} Statement Examples @@ -8837,9 +8942,22 @@ newline, the newline is output along with the rest of the string. A single @code{print} statement can make any number of lines this way. @cindex newlines, printing -The following is an example of printing a string that contains embedded newlines +The following is an example of printing a string that contains embedded +@ifinfo +newlines (the @samp{\n} is an escape sequence, used to represent the newline character; @pxref{Escape Sequences}): +@end ifinfo +@ifhtml +newlines +(the @samp{\n} is an escape sequence, used to represent the newline +character; @pxref{Escape Sequences}): +@end ifhtml +@ifnotinfo +@ifnothtml +newlines: +@end ifnothtml +@end ifnotinfo @example $ @kbd{awk 'BEGIN @{ print "line one\nline two\nline three" @}'} @@ -8943,7 +9061,7 @@ of items separated by commas. In the output, the items are normally separated by single spaces. However, this doesn't need to be the case; a single space is simply the default. Any string of characters may be used as the @dfn{output field separator} by setting the -built-in variable @code{OFS}. The initial value of this variable +predefined variable @code{OFS}. The initial value of this variable is the string @w{@code{" "}}---that is, a single space. The output from an entire @code{print} statement is called an @@ -9019,13 +9137,13 @@ more fully in @cindexawkfunc{sprintf} @cindex @code{OFMT} variable @cindex output, format specifier@comma{} @code{OFMT} -The built-in variable @code{OFMT} contains the default format specification +The predefined variable @code{OFMT} contains the format specification that @code{print} uses with @code{sprintf()} when it wants to convert a number to a string for printing. The default value of @code{OFMT} is @code{"%.6g"}. The way @code{print} prints numbers can be changed -by supplying different format specifications -as the value of @code{OFMT}, as shown in the following example: +by supplying a different format specification +for the value of @code{OFMT}, as shown in the following example: @example $ @kbd{awk 'BEGIN @{} @@ -9055,9 +9173,7 @@ With @code{printf} you can specify the width to use for each item, as well as various formatting choices for numbers (such as what output base to use, whether to print an exponent, whether to print a sign, and how many digits to print -after the decimal point). You do this by supplying a string, called -the @dfn{format string}, that controls how and where to print the other -arguments. +after the decimal point). @menu * Basic Printf:: Syntax of the @code{printf} statement. @@ -9077,10 +9193,10 @@ printf @var{format}, @var{item1}, @var{item2}, @dots{} @end example @noindent -The entire list of arguments may optionally be enclosed in parentheses. The -parentheses are necessary if any of the item expressions use the @samp{>} -relational operator; otherwise, it can be confused with an output redirection -(@pxref{Redirection}). +As print @code{print}, the entire list of arguments may optionally be +enclosed in parentheses. Here too, the parentheses are necessary if any +of the item expressions use the @samp{>} relational operator; otherwise, +it can be confused with an output redirection (@pxref{Redirection}). @cindex format specifiers The difference between @code{printf} and @code{print} is the @var{format} @@ -9103,10 +9219,10 @@ on @code{printf} statements. For example: @example $ @kbd{awk 'BEGIN @{} > @kbd{ORS = "\nOUCH!\n"; OFS = "+"} -> @kbd{msg = "Dont Panic!"} +> @kbd{msg = "Don\47t Panic!"} > @kbd{printf "%s\n", msg} > @kbd{@}'} -@print{} Dont Panic! +@print{} Don't Panic! @end example @noindent @@ -9128,7 +9244,7 @@ the field width. Here is a list of the format-control letters: @c @asis for docbook to come out right @table @asis @item @code{%c} -Print a number as an ASCII character; thus, @samp{printf "%c", +Print a number as a character; thus, @samp{printf "%c", 65} outputs the letter @samp{A}. The output for a string value is the first character of the string. @@ -9154,7 +9270,7 @@ a single byte (0--255). @item @code{%d}, @code{%i} Print a decimal integer. The two control letters are equivalent. -(The @samp{%i} specification is for compatibility with ISO C.) +(The @code{%i} specification is for compatibility with ISO C.) @item @code{%e}, @code{%E} Print a number in scientific (exponential) notation; @@ -9169,7 +9285,7 @@ prints @samp{1.950e+03}, with a total of four significant figures, three of which follow the decimal point. (The @samp{4.3} represents two modifiers, discussed in the next @value{SUBSECTION}.) -@samp{%E} uses @samp{E} instead of @samp{e} in the output. +@code{%E} uses @samp{E} instead of @samp{e} in the output. @item @code{%f} Print a number in floating-point notation. @@ -9195,16 +9311,16 @@ The special ``not a number'' value formats as @samp{-nan} or @samp{nan} (@pxref{Math Definitions}). @item @code{%F} -Like @samp{%f} but the infinity and ``not a number'' values are spelled +Like @code{%f} but the infinity and ``not a number'' values are spelled using uppercase letters. -The @samp{%F} format is a POSIX extension to ISO C; not all systems -support it. On those that don't, @command{gawk} uses @samp{%f} instead. +The @code{%F} format is a POSIX extension to ISO C; not all systems +support it. On those that don't, @command{gawk} uses @code{%f} instead. @item @code{%g}, @code{%G} Print a number in either scientific notation or in floating-point notation, whichever uses fewer characters; if the result is printed in -scientific notation, @samp{%G} uses @samp{E} instead of @samp{e}. +scientific notation, @code{%G} uses @samp{E} instead of @samp{e}. @item @code{%o} Print an unsigned octal integer @@ -9220,7 +9336,7 @@ are floating-point; it is provided primarily for compatibility with C.) @item @code{%x}, @code{%X} Print an unsigned hexadecimal integer; -@samp{%X} uses the letters @samp{A} through @samp{F} +@code{%X} uses the letters @samp{A} through @samp{F} instead of @samp{a} through @samp{f} (@pxref{Nondecimal-numbers}). @@ -9235,7 +9351,7 @@ argument and it ignores any modifiers. @quotation NOTE When using the integer format-control letters for values that are outside the range of the widest C integer type, @command{gawk} switches to -the @samp{%g} format specifier. If @option{--lint} is provided on the +the @code{%g} format specifier. If @option{--lint} is provided on the command line (@pxref{Options}), @command{gawk} warns about this. Other versions of @command{awk} may print invalid values or do something else entirely. @@ -9251,7 +9367,7 @@ values or do something else entirely. A format specification can also include @dfn{modifiers} that can control how much of the item's value is printed, as well as how much space it gets. The modifiers come between the @samp{%} and the format-control letter. -We will use the bullet symbol ``@bullet{}'' in the following examples to +We use the bullet symbol ``@bullet{}'' in the following examples to represent spaces in the output. Here are the possible modifiers, in the order in which they may appear: @@ -9282,7 +9398,7 @@ It is in fact a @command{gawk} extension, intended for use in translating messages at runtime. @xref{Printf Ordering}, which describes how and why to use positional specifiers. -For now, we will not use them. +For now, we ignore them. @item - The minus sign, used before the width modifier (see later on in @@ -9310,15 +9426,15 @@ to format is positive. The @samp{+} overrides the space modifier. @item # Use an ``alternate form'' for certain control letters. -For @samp{%o}, supply a leading zero. -For @samp{%x} and @samp{%X}, supply a leading @samp{0x} or @samp{0X} for +For @code{%o}, supply a leading zero. +For @code{%x} and @code{%X}, supply a leading @code{0x} or @samp{0X} for a nonzero result. -For @samp{%e}, @samp{%E}, @samp{%f}, and @samp{%F}, the result always +For @code{%e}, @code{%E}, @code{%f}, and @code{%F}, the result always contains a decimal point. -For @samp{%g} and @samp{%G}, trailing zeros are not removed from the result. +For @code{%g} and @code{%G}, trailing zeros are not removed from the result. @item 0 -A leading @samp{0} (zero) acts as a flag that indicates that output should be +A leading @samp{0} (zero) acts as a flag indicating that output should be padded with zeros instead of spaces. This applies only to the numeric output formats. This flag only has an effect when the field width is wider than the @@ -9504,7 +9620,7 @@ the @command{awk} program: @example awk 'BEGIN @{ print "Name Number" print "---- ------" @} - @{ printf "%-10s %s\n", $1, $2 @}' mail-list + @{ printf "%-10s %s\n", $1, $2 @}' mail-list @end example The above example mixes @code{print} and @code{printf} statements in @@ -9514,7 +9630,7 @@ same results: @example awk 'BEGIN @{ printf "%-10s %s\n", "Name", "Number" printf "%-10s %s\n", "----", "------" @} - @{ printf "%-10s %s\n", $1, $2 @}' mail-list + @{ printf "%-10s %s\n", $1, $2 @}' mail-list @end example @noindent @@ -9529,7 +9645,7 @@ emphasized by storing it in a variable, like this: awk 'BEGIN @{ format = "%-10s %s\n" printf format, "Name", "Number" printf format, "----", "------" @} - @{ printf format, $1, $2 @}' mail-list + @{ printf format, $1, $2 @}' mail-list @end example @c ENDOFRANGE printfs @@ -9550,7 +9666,7 @@ This is called @dfn{redirection}. @quotation NOTE When @option{--sandbox} is specified (@pxref{Options}), -redirecting output to files and pipes is disabled. +redirecting output to files, pipes and coprocesses is disabled. @end quotation A redirection appears after the @code{print} or @code{printf} statement. @@ -9647,17 +9763,11 @@ in an @command{awk} script run periodically for system maintenance: @example report = "mail bug-system" -print "Awk script failed:", $0 | report -m = ("at record number " FNR " of " FILENAME) -print m | report +print("Awk script failed:", $0) | report +print("at record number", FNR, "of", FILENAME) | report close(report) @end example -The message is built using string concatenation and saved in the variable -@code{m}. It's then sent down the pipeline to the @command{mail} program. -(The parentheses group the items to concatenate---see -@ref{Concatenation}.) - The @code{close()} function is called here because it's a good idea to close the pipe as soon as all the intended output has been sent to it. @xref{Close Files And Pipes}, @@ -9764,6 +9874,9 @@ The program builds up a list of command lines, using the @command{mv} utility to rename the files. It then sends the list to the shell for execution. +@xref{Shell Quoting}, for a function that can help in generating +command lines to be fed to the shell. + @docbook </sidebar> @end docbook @@ -9795,28 +9908,16 @@ uppercase characters converted to lowercase The program builds up a list of command lines, using the @command{mv} utility to rename the files. It then sends the list to the shell for execution. + +@xref{Shell Quoting}, for a function that can help in generating +command lines to be fed to the shell. @end cartouche @end ifnotdocbook @c ENDOFRANGE outre @c ENDOFRANGE reout -@node Special Files -@section Special @value{FFN}s in @command{gawk} -@c STARTOFRANGE gfn -@cindex @command{gawk}, file names in - -@command{gawk} provides a number of special @value{FN}s that it interprets -internally. These @value{FN}s provide access to standard file descriptors -and TCP/IP networking. - -@menu -* Special FD:: Special files for I/O. -* Special Network:: Special files for network communications. -* Special Caveats:: Things to watch out for. -@end menu - @node Special FD -@subsection Special Files for Standard Descriptors +@section Special Files for Standard Pre-Opened Data Streams @cindex standard input @cindex input, standard @cindex standard output @@ -9827,9 +9928,12 @@ and TCP/IP networking. @cindex files, descriptors, See file descriptors Running programs conventionally have three input and output streams -already available to them for reading and writing. These are known as -the @dfn{standard input}, @dfn{standard output}, and @dfn{standard error -output}. These streams are, by default, connected to your keyboard and screen, but +already available to them for reading and writing. These are known +as the @dfn{standard input}, @dfn{standard output}, and @dfn{standard +error output}. These open streams (and any other open file or pipe) +are often referred to by the technical term @dfn{file descriptors}. + +These streams are, by default, connected to your keyboard and screen, but they are often redirected with the shell, via the @samp{<}, @samp{<<}, @samp{>}, @samp{>>}, @samp{>&}, and @samp{|} operators. Standard error is typically used for writing error messages; the reason there are two separate @@ -9838,7 +9942,7 @@ redirected separately. @cindex differences in @command{awk} and @command{gawk}, error messages @cindex error handling -In other implementations of @command{awk}, the only way to write an error +In traditional implementations of @command{awk}, the only way to write an error message to standard error in an @command{awk} program is as follows: @example @@ -9864,19 +9968,19 @@ that is connected to your keyboard and screen. It represents the ``terminal,''@footnote{The ``tty'' in @file{/dev/tty} stands for ``Teletype,'' a serial terminal.} which on modern systems is a keyboard and screen, not a serial console.) -This usually has the same effect but not always: although the +This generally has the same effect but not always: although the standard error stream is usually the screen, it can be redirected; when that happens, writing to the screen is not correct. In fact, if @command{awk} is run from a background job, it may not have a terminal at all. Then opening @file{/dev/tty} fails. -@command{gawk} provides special @value{FN}s for accessing the three standard -streams. @value{COMMONEXT} It also provides syntax for accessing -any other inherited open files. If the @value{FN} matches -one of these special names when @command{gawk} redirects input or output, -then it directly uses the stream that the @value{FN} stands for. -These special @value{FN}s work for all operating systems that @command{gawk} +@command{gawk}, BWK @command{awk} and @command{mawk} provide +special @value{FN}s for accessing the three standard streams. +If the @value{FN} matches one of these special names when @command{gawk} +(or one of the others) redirects input or output, then it directly uses +the descriptor that the @value{FN} stands for. These special +@value{FN}s work for all operating systems that @command{gawk} has been ported to, not just those that are POSIX-compliant: @cindex common extensions, @code{/dev/stdin} special file @@ -9898,19 +10002,10 @@ The standard output (file descriptor 1). @item /dev/stderr The standard error output (file descriptor 2). - -@item /dev/fd/@var{N} -The file associated with file descriptor @var{N}. Such a file must -be opened by the program initiating the @command{awk} execution (typically -the shell). Unless special pains are taken in the shell from which -@command{gawk} is invoked, only descriptors 0, 1, and 2 are available. @end table -The @value{FN}s @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} -are aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and @file{/dev/fd/2}, -respectively. However, they are more self-explanatory. -The proper way to write an error message in a @command{gawk} program -is to use @file{/dev/stderr}, like this: +With these facilities, +the proper way to write an error message then becomes: @example print "Serious error detected!" > "/dev/stderr" @@ -9922,14 +10017,51 @@ Like any other redirection, the value must be a string. It is a common error to omit the quotes, which leads to confusing results. -Finally, using the @code{close()} function on a @value{FN} of the +@command{gawk} does not treat these @value{FN}s as special when +in POSIX compatibility mode. However, since BWK @command{awk} +supports them, @command{gawk} does support them even when +invoked with the @option{--traditional} option (@pxref{Options}). + +@node Special Files +@section Special @value{FFN}s in @command{gawk} +@c STARTOFRANGE gfn +@cindex @command{gawk}, file names in + +Besides access to standard input, stanard output, and standard error, +@command{gawk} provides access to any open file descriptor. +Additionally, there are special @value{FN}s reserved for +TCP/IP networking. + +@menu +* Other Inherited Files:: Accessing other open files with + @command{gawk}. +* Special Network:: Special files for network communications. +* Special Caveats:: Things to watch out for. +@end menu + +@node Other Inherited Files +@subsection Accessing Other Open Files With @command{gawk} + +Besides the @code{/dev/stdin}, @code{/dev/stdout}, and @code{/dev/stderr} +special @value{FN}s mentioned earlier, @command{gawk} provides syntax +for accessing any other inherited open file: + +@table @file +@item /dev/fd/@var{N} +The file associated with file descriptor @var{N}. Such a file must +be opened by the program initiating the @command{awk} execution (typically +the shell). Unless special pains are taken in the shell from which +@command{gawk} is invoked, only descriptors 0, 1, and 2 are available. +@end table + +The @value{FN}s @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} +are essentially aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and +@file{/dev/fd/2}, respectively. However, those names are more self-explanatory. + +Note that using @code{close()} on a @value{FN} of the form @code{"/dev/fd/@var{N}"}, for file descriptor numbers above two, does actually close the given file descriptor. -The @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} -special files are also recognized internally by several other -versions of @command{awk}. - @node Special Network @subsection Special Files for Network Communications @cindex networks, support for @@ -9958,15 +10090,20 @@ Full discussion is delayed until @node Special Caveats @subsection Special @value{FFN} Caveats -Here is a list of things to bear in mind when using the +Here are some things to bear in mind when using the special @value{FN}s that @command{gawk} provides: @itemize @value{BULLET} @cindex compatibility mode (@command{gawk}), file names @cindex file names, in compatibility mode @item -Recognition of these special @value{FN}s is disabled if @command{gawk} is in -compatibility mode (@pxref{Options}). +Recognition of the @value{FN}s for the three standard pre-opened +files is disabled only in POSIX mode. + +@item +Recognition of the other special @value{FN}s is disabled if @command{gawk} is in +compatibility mode (either @option{--traditional} or @option{--posix}; +@pxref{Options}). @item @command{gawk} @emph{always} @@ -10136,7 +10273,8 @@ to a string indicating the error. Note also that @samp{close(FILENAME)} has no ``magic'' effects on the implicit loop that reads through the files named on the command line. It is, more likely, a close of a file that was never opened with a -redirection, so @command{awk} silently does nothing. +redirection, so @command{awk} silently does nothing, except return +a negative value. @cindex @code{|} (vertical bar), @code{|&} operator (I/O), pipes@comma{} closing When using the @samp{|&} operator to communicate with a coprocess, @@ -10148,10 +10286,10 @@ the first argument is the name of the command or special file used to start the coprocess. The second argument should be a string, with either of the values @code{"to"} or @code{"from"}. Case does not matter. -As this is an advanced feature, a more complete discussion is +As this is an advanced feature, discussion is delayed until @ref{Two-way I/O}, -which discusses it in more detail and gives an example. +which describes it in more detail and gives an example. @cindex sidebar, Using @code{close()}'s Return Value @ifdocbook @@ -10182,7 +10320,7 @@ retval = close(command) # syntax error in many Unix awks The return value is @minus{}1 if the argument names something that was never opened with a redirection, or if there is a system problem closing the file or process. -In these cases, @command{gawk} sets the built-in variable +In these cases, @command{gawk} sets the predefined variable @code{ERRNO} to a string describing the problem. In @command{gawk}, @@ -10238,7 +10376,7 @@ retval = close(command) # syntax error in many Unix awks The return value is @minus{}1 if the argument names something that was never opened with a redirection, or if there is a system problem closing the file or process. -In these cases, @command{gawk} sets the built-in variable +In these cases, @command{gawk} sets the predefined variable @code{ERRNO} to a string describing the problem. In @command{gawk}, @@ -10285,15 +10423,15 @@ that modify the behavior of the format control letters. @item Output from both @code{print} and @code{printf} may be redirected to -files, pipes, and co-processes. +files, pipes, and coprocesses. @item @command{gawk} provides special file names for access to standard input, output and error, and for network communications. @item -Use @code{close()} to close open file, pipe and co-process redirections. -For co-processes, it is possible to close only one direction of the +Use @code{close()} to close open file, pipe and coprocess redirections. +For coprocesses, it is possible to close only one direction of the communications. @end itemize @@ -10427,7 +10565,7 @@ double-quotation marks. For example: @cindex strings, length limitations represents the string whose contents are @samp{parrot}. Strings in @command{gawk} can be of any length, and they can contain any of the possible -eight-bit ASCII characters including ASCII @value{NUL} (character code zero). +eight-bit ASCII characters including ASCII @sc{nul} (character code zero). Other @command{awk} implementations may have difficulty with some character codes. @@ -10607,7 +10745,7 @@ if (/barfly/ || /camelot/) @noindent are exactly equivalent. One rather bizarre consequence of this rule is that the following -Boolean expression is valid, but does not do what the user probably +Boolean expression is valid, but does not do what its author probably intended: @example @@ -10653,10 +10791,9 @@ Modern implementations of @command{awk}, including @command{gawk}, allow the third argument of @code{split()} to be a regexp constant, but some older implementations do not. @value{DARKCORNER} -This can lead to confusion when attempting to use regexp constants -as arguments to user-defined functions -(@pxref{User-defined}). -For example: +Because some built-in functions accept regexp constants as arguments, +it can be confusing when attempting to use regexp constants as arguments +to user-defined functions (@pxref{User-defined}). For example: @example function mysub(pat, repl, str, global) @@ -10724,24 +10861,24 @@ variable's current value. Variables are given new values with @dfn{decrement operators}. @xref{Assignment Ops}. In addition, the @code{sub()} and @code{gsub()} functions can -change a variable's value, and the @code{match()}, @code{patsplit()} -and @code{split()} functions can change the contents of their +change a variable's value, and the @code{match()}, @code{split()} +and @code{patsplit()} functions can change the contents of their array parameters. @xref{String Functions}. @cindex variables, built-in @cindex variables, initializing A few variables have special built-in meanings, such as @code{FS} (the field separator), and @code{NF} (the number of fields in the current input -record). @xref{Built-in Variables}, for a list of the built-in variables. -These built-in variables can be used and assigned just like all other +record). @xref{Built-in Variables}, for a list of the predefined variables. +These predefined variables can be used and assigned just like all other variables, but their values are also used or changed automatically by -@command{awk}. All built-in variables' names are entirely uppercase. +@command{awk}. All predefined variables' names are entirely uppercase. Variables in @command{awk} can be assigned either numeric or string values. The kind of value a variable holds can change over the life of a program. By default, variables are initialized to the empty string, which is zero if converted to a number. There is no need to explicitly -``initialize'' a variable in @command{awk}, +initialize a variable in @command{awk}, which is what you would do in C and in most other traditional languages. @node Assignment Options @@ -10861,7 +10998,7 @@ Strings that can't be interpreted as valid numbers convert to zero. @cindex @code{CONVFMT} variable The exact manner in which numbers are converted into strings is controlled -by the @command{awk} built-in variable @code{CONVFMT} (@pxref{Built-in Variables}). +by the @command{awk} predefined variable @code{CONVFMT} (@pxref{Built-in Variables}). Numbers are converted using the @code{sprintf()} function with @code{CONVFMT} as the format specifier @@ -10978,8 +11115,8 @@ $ @kbd{echo 4,321 | LC_ALL=en_DK.utf-8 gawk '@{ print $1 + 1 @}'} @noindent The @code{en_DK.utf-8} locale is for English in Denmark, where the comma acts as the decimal point separator. In the normal @code{"C"} locale, @command{gawk} -treats @samp{4,321} as @samp{4}, while in the Danish locale, it's treated -as the full number, 4.321. +treats @samp{4,321} as 4, while in the Danish locale, it's treated +as the full number including the fractional part, 4.321. Some earlier versions of @command{gawk} fully complied with this aspect of the standard. However, many users in non-English locales complained @@ -11535,7 +11672,7 @@ awk '/[=]=/' /dev/null @end example @command{gawk} does not have this problem; BWK @command{awk} -and @command{mawk} also do not (@pxref{Other Versions}). +and @command{mawk} also do not. @docbook </sidebar> @@ -11581,7 +11718,7 @@ awk '/[=]=/' /dev/null @end example @command{gawk} does not have this problem; BWK @command{awk} -and @command{mawk} also do not (@pxref{Other Versions}). +and @command{mawk} also do not. @end cartouche @end ifnotdocbook @c ENDOFRANGE exas @@ -11893,7 +12030,7 @@ attribute. @item Fields, @code{getline} input, @code{FILENAME}, @code{ARGV} elements, @code{ENVIRON} elements, and the elements of an array created by -@code{patsplit()}, @code{split()} and @code{match()} that are numeric +@code{match()}, @code{split()} and @code{patsplit()} that are numeric strings have the @var{strnum} attribute. Otherwise, they have the @var{string} attribute. Uninitialized variables also have the @var{strnum} attribute. @@ -12048,22 +12185,23 @@ Thus, the six-character input string @w{@samp{ +3.14}} receives the The following examples print @samp{1} when the comparison between the two different constants is true, @samp{0} otherwise: +@c 22.9.2014: Tested with mawk and BWK awk, got same results. @example -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == " +3.14" @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == " +3.14") @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == "+3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == "+3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == "3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == "3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == 3.14 @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == 3.14) @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == " +3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == " +3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == "+3.14" @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == "+3.14") @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == "3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == "3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == 3.14 @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == 3.14) @}'} @ii{True} @print{} 1 @end example @@ -12137,9 +12275,8 @@ part of the test always succeeds. Because the operators are so similar, this kind of error is very difficult to spot when scanning the source code. -@cindex @command{gawk}, comparison operators and -The following table of expressions illustrates the kind of comparison -@command{gawk} performs, as well as what the result of the comparison is: +The following list of expressions illustrates the kinds of comparisons +@command{awk} performs, as well as what the result of each comparison is: @table @code @item 1.5 <= 2.0 @@ -12212,7 +12349,7 @@ dynamic regexp (@pxref{Regexp Usage}; also @cindex @command{awk}, regexp constants and @cindex regexp constants -In modern implementations of @command{awk}, a constant regular +A constant regular expression in slashes by itself is also an expression. The regexp @code{/@var{regexp}/} is an abbreviation for the following comparison expression: @@ -12232,7 +12369,7 @@ where this is discussed in more detail. The POSIX standard says that string comparison is performed based on the locale's @dfn{collating order}. This is the order in which characters sort, as defined by the locale (for more discussion, -@pxref{Ranges and Locales}). This order is usually very different +@pxref{Locales}). This order is usually very different from the results obtained when doing straight character-by-character comparison.@footnote{Technically, string comparison is supposed to behave the same way as if the strings are compared with the C @@ -12312,7 +12449,7 @@ no substring @samp{foo} in the record. True if at least one of @var{boolean1} or @var{boolean2} is true. For example, the following statement prints all records in the input that contain @emph{either} @samp{edu} or -@samp{li} or both: +@samp{li}: @example if ($0 ~ /edu/ || $0 ~ /li/) print @@ -12321,6 +12458,9 @@ if ($0 ~ /edu/ || $0 ~ /li/) print The subexpression @var{boolean2} is evaluated only if @var{boolean1} is false. This can make a difference when @var{boolean2} contains expressions that have side effects. +(Thus, this test never really distinguishes records that contain both +@samp{edu} and @samp{li}---as soon as @samp{edu} is matched, +the full test succeeds.) @item ! @var{boolean} True if @var{boolean} is false. For example, @@ -12330,7 +12470,7 @@ variable is not defined: @example BEGIN @{ if (! ("HOME" in ENVIRON)) - print "no home!" @} + print "no home!" @} @end example (The @code{in} operator is described in @@ -12629,7 +12769,7 @@ expression because the first @samp{$} has higher precedence than the @samp{++}; to avoid the problem the expression can be rewritten as @samp{$($0++)--}. -This table presents @command{awk}'s operators, in order of highest +This list presents @command{awk}'s operators, in order of highest to lowest precedence: @c @asis for docbook to come out right @@ -12786,8 +12926,8 @@ system about the local character set and language. The ISO C standard defines a default @code{"C"} locale, which is an environment that is typical of what many C programmers are used to. -Once upon a time, the locale setting used to affect regexp matching -(@pxref{Ranges and Locales}), but this is no longer true. +Once upon a time, the locale setting used to affect regexp matching, +but this is no longer true (@pxref{Ranges and Locales}). Locales can affect record splitting. For the normal case of @samp{RS = "\n"}, the locale is largely irrelevant. For other single-character @@ -12799,7 +12939,7 @@ character}, to find the record terminator. Locales can affect how dates and times are formatted (@pxref{Time Functions}). For example, a common way to abbreviate the date September 4, 2015 in the United States is ``9/4/15.'' In many countries in -Europe, however, it is abbreviated ``4.9.15.'' Thus, the @samp{%x} +Europe, however, it is abbreviated ``4.9.15.'' Thus, the @code{%x} specification in a @code{"US"} locale might produce @samp{9/4/15}, while in a @code{"EUROPE"} locale, it might produce @samp{4.9.15}. @@ -12841,7 +12981,8 @@ Locales can influence the conversions. @item @command{awk} provides the usual arithmetic operators (addition, subtraction, multiplication, division, modulus), and unary plus and minus. -It also provides comparison operators, boolean operators, and regexp +It also provides comparison operators, boolean operators, array membership +testing, and regexp matching operators. String concatenation is accomplished by placing two expressions next to each other; there is no explicit operator. The three-operand @samp{?:} operator provides an ``if-else'' test within @@ -12856,7 +12997,7 @@ In @command{awk}, a value is considered to be true if it is non-zero @emph{or} non-null. Otherwise, the value is false. @item -A value's type is set upon each assignment and may change over its +A variable's type is set upon each assignment and may change over its lifetime. The type determines how it behaves in comparisons (string or numeric). @@ -12888,7 +13029,7 @@ program, and occasionally the format for data read as input. As you have already seen, each @command{awk} statement consists of a pattern with an associated action. This @value{CHAPTER} describes how you build patterns and actions, what kinds of things you can do within -actions, and @command{awk}'s built-in variables. +actions, and @command{awk}'s predefined variables. The pattern-action rules and the statements available for use within actions form the core of @command{awk} programming. @@ -12903,7 +13044,7 @@ building something useful. * Action Overview:: What goes into an action. * Statements:: Describes the various control statements in detail. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * Pattern Action Summary:: Patterns and Actions summary. @end menu @@ -12936,7 +13077,7 @@ is nonzero (if a number) or non-null (if a string). (@xref{Expression Patterns}.) @item @var{begpat}, @var{endpat} -A pair of patterns separated by a comma, specifying a range of records. +A pair of patterns separated by a comma, specifying a @dfn{range} of records. The range includes both the initial record that matches @var{begpat} and the final record that matches @var{endpat}. (@xref{Ranges}.) @@ -13026,8 +13167,8 @@ $ @kbd{awk '$1 ~ /li/ @{ print $2 @}' mail-list} @cindex regexp constants, as patterns @cindex patterns, regexp constants as A regexp constant as a pattern is also a special case of an expression -pattern. The expression @code{/li/} has the value one if @samp{li} -appears in the current input record. Thus, as a pattern, @code{/li/} +pattern. The expression @samp{/li/} has the value one if @samp{li} +appears in the current input record. Thus, as a pattern, @samp{/li/} matches any record containing @samp{li}. @cindex Boolean expressions, as patterns @@ -13209,7 +13350,7 @@ input is read. For example: @example $ @kbd{awk '} > @kbd{BEGIN @{ print "Analysis of \"li\"" @}} -> @kbd{/li/ @{ ++n @}} +> @kbd{/li/ @{ ++n @}} > @kbd{END @{ print "\"li\" appears in", n, "records." @}' mail-list} @print{} Analysis of "li" @print{} "li" appears in 4 records. @@ -13289,9 +13430,10 @@ The POSIX standard specifies that @code{NF} is available in an @code{END} rule. It contains the number of fields from the last input record. Most probably due to an oversight, the standard does not say that @code{$0} is also preserved, although logically one would think that it should be. -In fact, @command{gawk} does preserve the value of @code{$0} for use in -@code{END} rules. Be aware, however, that BWK @command{awk}, and possibly -other implementations, do not. +In fact, all of BWK @command{awk}, @command{mawk}, and @command{gawk} +preserve the value of @code{$0} for use in @code{END} rules. Be aware, +however, that some other implementations and many older versions +of Unix @command{awk} do not. The third point follows from the first two. The meaning of @samp{print} inside a @code{BEGIN} or @code{END} rule is the same as always: @@ -13386,8 +13528,8 @@ level of the @command{awk} program. @cindex @code{next} statement, @code{BEGINFILE}/@code{ENDFILE} patterns and The @code{next} statement (@pxref{Next Statement}) is not allowed inside -either a @code{BEGINFILE} or and @code{ENDFILE} rule. The @code{nextfile} -statement (@pxref{Nextfile Statement}) is allowed only inside a +either a @code{BEGINFILE} or an @code{ENDFILE} rule. The @code{nextfile} +statement is allowed only inside a @code{BEGINFILE} rule, but not inside an @code{ENDFILE} rule. @cindex @code{getline} statement, @code{BEGINFILE}/@code{ENDFILE} patterns and @@ -13451,7 +13593,7 @@ There are two ways to get the value of the shell variable into the body of the @command{awk} program. @cindex shells, quoting -The most common method is to use shell quoting to substitute +A common method is to use shell quoting to substitute the variable's value into the program inside the script. For example, consider the following program: @@ -13708,20 +13850,21 @@ If the @var{condition} is true, it executes the statement @var{body}. is not zero and not a null string.) @end ifinfo After @var{body} has been executed, -@var{condition} is tested again, and if it is still true, @var{body} is -executed again. This process repeats until the @var{condition} is no longer -true. If the @var{condition} is initially false, the body of the loop is -never executed and @command{awk} continues with the statement following +@var{condition} is tested again, and if it is still true, @var{body} +executes again. This process repeats until the @var{condition} is no longer +true. If the @var{condition} is initially false, the body of the loop +never executes and @command{awk} continues with the statement following the loop. This example prints the first three fields of each record, one per line: @example -awk '@{ - i = 1 - while (i <= 3) @{ - print $i - i++ - @} +awk ' +@{ + i = 1 + while (i <= 3) @{ + print $i + i++ + @} @}' inventory-shipped @end example @@ -13755,14 +13898,14 @@ do while (@var{condition}) @end example -Even if the @var{condition} is false at the start, the @var{body} is -executed at least once (and only once, unless executing @var{body} +Even if the @var{condition} is false at the start, the @var{body} +executes at least once (and only once, unless executing @var{body} makes @var{condition} true). Contrast this with the corresponding @code{while} statement: @example while (@var{condition}) - @var{body} + @var{body} @end example @noindent @@ -13772,11 +13915,11 @@ The following is an example of a @code{do} statement: @example @{ - i = 1 - do @{ - print $0 - i++ - @} while (i <= 10) + i = 1 + do @{ + print $0 + i++ + @} while (i <= 10) @} @end example @@ -13813,9 +13956,10 @@ compares it against the desired number of iterations. For example: @example -awk '@{ - for (i = 1; i <= 3; i++) - print $i +awk ' +@{ + for (i = 1; i <= 3; i++) + print $i @}' inventory-shipped @end example @@ -13843,7 +13987,7 @@ between 1 and 100: @example for (i = 1; i <= 100; i *= 2) - print i + print i @end example If there is nothing to be done, any of the three expressions in the @@ -14163,7 +14307,7 @@ The @code{next} statement is not allowed inside @code{BEGINFILE} and @cindex functions, user-defined, @code{next}/@code{nextfile} statements and According to the POSIX standard, the behavior is undefined if the @code{next} statement is used in a @code{BEGIN} or @code{END} rule. -@command{gawk} treats it as a syntax error. Although POSIX permits it, +@command{gawk} treats it as a syntax error. Although POSIX does not disallow it, most other @command{awk} implementations don't allow the @code{next} statement inside function bodies (@pxref{User-defined}). Just as with any other @code{next} statement, a @code{next} statement inside a function @@ -14218,7 +14362,7 @@ opened with redirections. It is not related to the main processing that @quotation NOTE For many years, @code{nextfile} was a -@command{gawk} extension. As of September, 2012, it was accepted for +common extension. In September, 2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @end quotation @@ -14227,8 +14371,8 @@ See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @cindex @code{nextfile} statement, user-defined functions and @cindex Brian Kernighan's @command{awk} @cindex @command{mawk} utility -The current version of BWK @command{awk}, and @command{mawk} (@pxref{Other -Versions}) also support @code{nextfile}. However, they don't allow the +The current version of BWK @command{awk}, and @command{mawk} +also support @code{nextfile}. However, they don't allow the @code{nextfile} statement inside function bodies (@pxref{User-defined}). @command{gawk} does; a @code{nextfile} inside a function body reads the next record and starts processing it with the first rule in the program, @@ -14260,8 +14404,8 @@ the program to stop immediately. An @code{exit} statement that is not part of a @code{BEGIN} or @code{END} rule stops the execution of any further automatic rules for the current record, skips reading any remaining input records, and executes the -@code{END} rule if there is one. -Any @code{ENDFILE} rules are also skipped; they are not executed. +@code{END} rule if there is one. @command{gawk} also skips +any @code{ENDFILE} rules; they do not execute. In such a case, if you don't want the @code{END} rule to do its job, set a variable @@ -14309,11 +14453,11 @@ results across different operating systems. @c ENDOFRANGE accs @node Built-in Variables -@section Built-in Variables +@section Predefined Variables @c STARTOFRANGE bvar -@cindex built-in variables +@cindex predefined variables @c STARTOFRANGE varb -@cindex variables, built-in +@cindex variables, predefined Most @command{awk} variables are available to use for your own purposes; they never change unless your program assigns values to @@ -14324,8 +14468,8 @@ to tell @command{awk} how to do certain things. Others are set automatically by @command{awk}, so that they carry information from the internal workings of @command{awk} to your program. -@cindex @command{gawk}, built-in variables and -This @value{SECTION} documents all of @command{gawk}'s built-in variables, +@cindex @command{gawk}, predefined variables and +This @value{SECTION} documents all of @command{gawk}'s predefined variables, most of which are also documented in the @value{CHAPTER}s describing their areas of activity. @@ -14340,7 +14484,7 @@ their areas of activity. @node User-modified @subsection Built-in Variables That Control @command{awk} @c STARTOFRANGE bvaru -@cindex built-in variables, user-modifiable +@cindex predefined variables, user-modifiable @c STARTOFRANGE nmbv @cindex user-modifiable variables @@ -14369,7 +14513,7 @@ respectively, should use binary I/O. A string value of @code{"rw"} or @code{"wr"} indicates that all files should use binary I/O. Any other string value is treated the same as @code{"rw"}, but causes @command{gawk} to generate a warning message. @code{BINMODE} is described in more -detail in @ref{PC Using}. @command{mawk} @pxref{Other Versions}), +detail in @ref{PC Using}. @command{mawk} (@pxref{Other Versions}), also supports this variable, but only using numeric values. @cindex @code{CONVFMT} variable @@ -14496,7 +14640,7 @@ printing with the @code{print} statement. It works by being passed as the first argument to the @code{sprintf()} function (@pxref{String Functions}). Its default value is @code{"%.6g"}. Earlier versions of @command{awk} -also used @code{OFMT} to specify the format for converting numbers to +used @code{OFMT} to specify the format for converting numbers to strings in general expressions; this is now done by @code{CONVFMT}. @cindex @code{sprintf()} function, @code{OFMT} variable and @@ -14577,9 +14721,9 @@ The default value of @code{TEXTDOMAIN} is @code{"messages"}. @subsection Built-in Variables That Convey Information @c STARTOFRANGE bvconi -@cindex built-in variables, conveying information +@cindex predefined variables, conveying information @c STARTOFRANGE vbconi -@cindex variables, built-in, conveying information +@cindex variables, predefined conveying information The following is an alphabetical list of variables that @command{awk} sets automatically on certain occasions in order to provide information to your program. @@ -14648,8 +14792,8 @@ successive instances of the same @value{FN} on the command line. @cindex file names, distinguishing While you can change the value of @code{ARGIND} within your @command{awk} -program, @command{gawk} automatically sets it to a new value when the -next file is opened. +program, @command{gawk} automatically sets it to a new value when it +opens the next file. @cindex @code{ENVIRON} array @cindex environment variables, in @code{ENVIRON} array @@ -14714,10 +14858,10 @@ can give @code{FILENAME} a value. @cindex @code{FNR} variable @item @code{FNR} -The current record number in the current file. @code{FNR} is -incremented each time a new record is read -(@pxref{Records}). It is reinitialized -to zero each time a new input file is started. +The current record number in the current file. @command{awk} increments +@code{FNR} each time it reads a new record (@pxref{Records}). +@command{awk} resets @code{FNR} to zero each time it starts a new +input file. @cindex @code{NF} variable @item @code{NF} @@ -14749,7 +14893,7 @@ array causes a fatal error. Any attempt to assign to an element of The number of input records @command{awk} has processed since the beginning of the program's execution (@pxref{Records}). -@code{NR} is incremented each time a new record is read. +@command{awk} increments @code{NR} each time it reads a new record. @cindex @command{gawk}, @code{PROCINFO} array in @cindex @code{PROCINFO} array @@ -14829,7 +14973,7 @@ The parent process ID of the current process. @item PROCINFO["sorted_in"] If this element exists in @code{PROCINFO}, its value controls the order in which array indices will be processed by -@samp{for (@var{index} in @var{array})} loops. +@samp{for (@var{indx} in @var{array})} loops. Since this is an advanced feature, we defer the full description until later; see @ref{Scanning an Array}. @@ -14850,7 +14994,7 @@ The version of @command{gawk}. The following additional elements in the array are available to provide information about the MPFR and GMP libraries -if your version of @command{gawk} supports arbitrary precision numbers +if your version of @command{gawk} supports arbitrary precision arithmetic (@pxref{Arbitrary Precision Arithmetic}): @table @code @@ -14899,14 +15043,14 @@ The @code{PROCINFO} array has the following additional uses: @itemize @value{BULLET} @item -It may be used to cause coprocesses to communicate over pseudo-ttys -instead of through two-way pipes; this is discussed further in -@ref{Two-way I/O}. - -@item It may be used to provide a timeout when reading from any open input file, pipe, or coprocess. @xref{Read Timeout}, for more information. + +@item +It may be used to cause coprocesses to communicate over pseudo-ttys +instead of through two-way pipes; this is discussed further in +@ref{Two-way I/O}. @end itemize @cindex @code{RLENGTH} variable @@ -14937,9 +15081,13 @@ the record separator. It is set every time a record is read. @cindex @code{SYMTAB} array @cindex differences in @command{awk} and @command{gawk}, @code{SYMTAB} variable @item @code{SYMTAB #} -An array whose indices are the names of all currently defined -global variables and arrays in the program. The array may be used -for indirect access to read or write the value of a variable: +An array whose indices are the names of all defined global variables and +arrays in the program. @code{SYMTAB} makes @command{gawk}'s symbol table +visible to the @command{awk} programmer. It is built as @command{gawk} +parses the program and is complete before the program starts to run. + +The array may be used for indirect access to read or write the value of +a variable: @example foo = 5 @@ -15194,6 +15342,12 @@ following @option{-v} are passed on to the @command{awk} program. (@xref{Getopt Function}, for an @command{awk} library function that parses command-line options.) +When designing your program, you should choose options that don't +conflict with @command{gawk}'s, since it will process any options +that it accepts before passing the rest of the command line on to +your program. Using @samp{#!} with the @option{-E} option may help +(@pxref{Executable Scripts}, and @pxref{Options}). + @node Pattern Action Summary @section Summary @@ -15228,7 +15382,7 @@ input and output statements, and deletion statements. The control statements in @command{awk} are @code{if}-@code{else}, @code{while}, @code{for}, and @code{do}-@code{while}. @command{gawk} adds the @code{switch} statement. There are two flavors of @code{for} -statement: one for for performing general looping, and the other iterating +statement: one for performing general looping, and the other for iterating through an array. @item @@ -15245,12 +15399,17 @@ The @code{exit} statement terminates your program. When executed from an action (or function body) it transfers control to the @code{END} statements. From an @code{END} statement body, it exits immediately. You may pass an optional numeric value to be used -at @command{awk}'s exit status. +as @command{awk}'s exit status. @item -Some built-in variables provide control over @command{awk}, mainly for I/O. +Some predefined variables provide control over @command{awk}, mainly for I/O. Other variables convey information from @command{awk} to your program. +@item +@code{ARGC} and @code{ARGV} make the command-line arguments available +to your program. Manipulating them from a @code{BEGIN} rule lets you +control how @command{awk} will process the provided @value{DF}s. + @end itemize @node Arrays @@ -15271,24 +15430,13 @@ The @value{CHAPTER} moves on to discuss @command{gawk}'s facility for sorting arrays, and ends with a brief description of @command{gawk}'s ability to support true arrays of arrays. -@cindex variables, names of -@cindex functions, names of -@cindex arrays, names of, and names of functions/variables -@cindex names, arrays/variables -@cindex namespace issues -@command{awk} maintains a single set -of names that may be used for naming variables, arrays, and functions -(@pxref{User-defined}). -Thus, you cannot have a variable and an array with the same name in the -same @command{awk} program. - @menu * Array Basics:: The basics of arrays. -* Delete:: The @code{delete} statement removes an element - from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in @command{awk}. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The @code{delete} statement removes an element + from an array. * Multidimensional:: Emulating multidimensional arrays in @command{awk}. * Arrays of Arrays:: True multidimensional arrays. @@ -15334,7 +15482,7 @@ as a variable) in the same @command{awk} program. Arrays in @command{awk} superficially resemble arrays in other programming languages, but there are fundamental differences. In @command{awk}, it isn't necessary to specify the size of an array before starting to use it. -Additionally, any number or string in @command{awk}, not just consecutive integers, +Additionally, any number or string, not just consecutive integers, may be used as an array index. In most other languages, arrays must be @dfn{declared} before use, @@ -15716,14 +15864,14 @@ begin with a number: @example @c file eg/misc/arraymax.awk @{ - if ($1 > max) - max = $1 - arr[$1] = $0 + if ($1 > max) + max = $1 + arr[$1] = $0 @} END @{ - for (x = 1; x <= max; x++) - print arr[x] + for (x = 1; x <= max; x++) + print arr[x] @} @c endfile @end example @@ -15763,9 +15911,9 @@ program's @code{END} rule, as follows: @example END @{ - for (x = 1; x <= max; x++) - if (x in arr) - print arr[x] + for (x = 1; x <= max; x++) + if (x in arr) + print arr[x] @} @end example @@ -15787,7 +15935,7 @@ an array: @example for (@var{var} in @var{array}) - @var{body} + @var{body} @end example @noindent @@ -15860,7 +16008,7 @@ BEGIN @{ @} @end example -Here is what happens when run with @command{gawk}: +Here is what happens when run with @command{gawk} (and @command{mawk}): @example $ @kbd{gawk -f loopcheck.awk} @@ -15978,7 +16126,8 @@ does not affect the loop. For example: @example -$ @kbd{gawk 'BEGIN @{} +$ @kbd{gawk '} +> @kbd{BEGIN @{} > @kbd{ a[4] = 4} > @kbd{ a[3] = 3} > @kbd{ for (i in a)} @@ -15986,7 +16135,8 @@ $ @kbd{gawk 'BEGIN @{} > @kbd{@}'} @print{} 4 4 @print{} 3 3 -$ @kbd{gawk 'BEGIN @{} +$ @kbd{gawk '} +> @kbd{BEGIN @{} > @kbd{ PROCINFO["sorted_in"] = "@@ind_str_asc"} > @kbd{ a[4] = 4} > @kbd{ a[3] = 3} @@ -16035,118 +16185,6 @@ the @code{delete} statement. In addition, @command{gawk} provides built-in functions for sorting arrays; see @ref{Array Sorting Functions}. -@node Delete -@section The @code{delete} Statement -@cindex @code{delete} statement -@cindex deleting elements in arrays -@cindex arrays, elements, deleting -@cindex elements in arrays, deleting - -To remove an individual element of an array, use the @code{delete} -statement: - -@example -delete @var{array}[@var{index-expression}] -@end example - -Once an array element has been deleted, any value the element once -had is no longer available. It is as if the element had never -been referred to or been given a value. -The following is an example of deleting elements in an array: - -@example -for (i in frequencies) - delete frequencies[i] -@end example - -@noindent -This example removes all the elements from the array @code{frequencies}. -Once an element is deleted, a subsequent @code{for} statement to scan the array -does not report that element and the @code{in} operator to check for -the presence of that element returns zero (i.e., false): - -@example -delete foo[4] -if (4 in foo) - print "This will never be printed" -@end example - -@cindex null strings, and deleting array elements -It is important to note that deleting an element is @emph{not} the -same as assigning it a null value (the empty string, @code{""}). -For example: - -@example -foo[4] = "" -if (4 in foo) - print "This is printed, even though foo[4] is empty" -@end example - -@cindex lint checking, array elements -It is not an error to delete an element that does not exist. -However, if @option{--lint} is provided on the command line -(@pxref{Options}), -@command{gawk} issues a warning message when an element that -is not in the array is deleted. - -@cindex common extensions, @code{delete} to delete entire arrays -@cindex extensions, common@comma{} @code{delete} to delete entire arrays -@cindex arrays, deleting entire contents -@cindex deleting entire arrays -@cindex @code{delete} @var{array} -@cindex differences in @command{awk} and @command{gawk}, array elements, deleting -All the elements of an array may be deleted with a single statement -by leaving off the subscript in the @code{delete} statement, -as follows: - - -@example -delete @var{array} -@end example - -Using this version of the @code{delete} statement is about three times -more efficient than the equivalent loop that deletes each element one -at a time. - -@cindex Brian Kernighan's @command{awk} -@quotation NOTE -For many years, -using @code{delete} without a subscript was a @command{gawk} extension. -As of September, 2012, it was accepted for -inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, -the Austin Group website}. This form of the @code{delete} statement is also supported -by BWK @command{awk} and @command{mawk}, as well as -by a number of other implementations (@pxref{Other Versions}). -@end quotation - -@cindex portability, deleting array elements -@cindex Brennan, Michael -The following statement provides a portable but nonobvious way to clear -out an array:@footnote{Thanks to Michael Brennan for pointing this out.} - -@example -split("", array) -@end example - -@cindex @code{split()} function, array elements@comma{} deleting -The @code{split()} function -(@pxref{String Functions}) -clears out the target array first. This call asks it to split -apart the null string. Because there is no data to split out, the -function simply clears the array and then returns. - -@quotation CAUTION -Deleting an array does not change its type; you cannot -delete an array and then use the array's name as a scalar -(i.e., a regular variable). For example, the following does not work: - -@example -a[1] = 3 -delete a -a = 3 -@end example -@end quotation - @node Numeric Array Subscripts @section Using Numbers to Subscript Arrays @@ -16158,7 +16196,7 @@ An important aspect to remember about arrays is that @emph{array subscripts are always strings}. When a numeric value is used as a subscript, it is converted to a string value before being used for subscripting (@pxref{Conversion}). -This means that the value of the built-in variable @code{CONVFMT} can +This means that the value of the predefined variable @code{CONVFMT} can affect how your program accesses elements of an array. For example: @example @@ -16187,7 +16225,7 @@ since @code{"12.15"} is different from @code{"12.153"}. @cindex integer array indices According to the rules for conversions (@pxref{Conversion}), integer -values are always converted to strings as integers, no matter what the +values always convert to strings as integers, no matter what the value of @code{CONVFMT} may happen to be. So the usual case of the following works: @@ -16210,7 +16248,7 @@ and all refer to the same element! As with many things in @command{awk}, the majority of the time -things work as one would expect them to. But it is useful to have a precise +things work as you would expect them to. But it is useful to have a precise knowledge of the actual rules since they can sometimes have a subtle effect on your programs. @@ -16274,6 +16312,119 @@ Even though it is somewhat unusual, the null string if @option{--lint} is provided on the command line (@pxref{Options}). +@node Delete +@section The @code{delete} Statement +@cindex @code{delete} statement +@cindex deleting elements in arrays +@cindex arrays, elements, deleting +@cindex elements in arrays, deleting + +To remove an individual element of an array, use the @code{delete} +statement: + +@example +delete @var{array}[@var{index-expression}] +@end example + +Once an array element has been deleted, any value the element once +had is no longer available. It is as if the element had never +been referred to or been given a value. +The following is an example of deleting elements in an array: + +@example +for (i in frequencies) + delete frequencies[i] +@end example + +@noindent +This example removes all the elements from the array @code{frequencies}. +Once an element is deleted, a subsequent @code{for} statement to scan the array +does not report that element and the @code{in} operator to check for +the presence of that element returns zero (i.e., false): + +@example +delete foo[4] +if (4 in foo) + print "This will never be printed" +@end example + +@cindex null strings, and deleting array elements +It is important to note that deleting an element is @emph{not} the +same as assigning it a null value (the empty string, @code{""}). +For example: + +@example +foo[4] = "" +if (4 in foo) + print "This is printed, even though foo[4] is empty" +@end example + +@cindex lint checking, array elements +It is not an error to delete an element that does not exist. +However, if @option{--lint} is provided on the command line +(@pxref{Options}), +@command{gawk} issues a warning message when an element that +is not in the array is deleted. + +@cindex common extensions, @code{delete} to delete entire arrays +@cindex extensions, common@comma{} @code{delete} to delete entire arrays +@cindex arrays, deleting entire contents +@cindex deleting entire arrays +@cindex @code{delete} @var{array} +@cindex differences in @command{awk} and @command{gawk}, array elements, deleting +All the elements of an array may be deleted with a single statement +by leaving off the subscript in the @code{delete} statement, +as follows: + + +@example +delete @var{array} +@end example + +Using this version of the @code{delete} statement is about three times +more efficient than the equivalent loop that deletes each element one +at a time. + +This form of the @code{delete} statement is also supported +by BWK @command{awk} and @command{mawk}, as well as +by a number of other implementations. + +@cindex Brian Kernighan's @command{awk} +@quotation NOTE +For many years, using @code{delete} without a subscript was a common +extension. In September, 2012, it was accepted for inclusion into the +POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, +the Austin Group website}. +@end quotation + +@cindex portability, deleting array elements +@cindex Brennan, Michael +The following statement provides a portable but nonobvious way to clear +out an array:@footnote{Thanks to Michael Brennan for pointing this out.} + +@example +split("", array) +@end example + +@cindex @code{split()} function, array elements@comma{} deleting +The @code{split()} function +(@pxref{String Functions}) +clears out the target array first. This call asks it to split +apart the null string. Because there is no data to split out, the +function simply clears the array and then returns. + +@quotation CAUTION +Deleting all the elements from an array does not change its type; you cannot +clear an array and then use the array's name as a scalar +(i.e., a regular variable). For example, the following does not work: + +@example +a[1] = 3 +delete a +a = 3 +@end example +@end quotation + @node Multidimensional @section Multidimensional Arrays @@ -16285,7 +16436,7 @@ on the command line (@pxref{Options}). @cindex arrays, multidimensional A multidimensional array is an array in which an element is identified by a sequence of indices instead of a single index. For example, a -two-dimensional array requires two indices. The usual way (in most +two-dimensional array requires two indices. The usual way (in many languages, including @command{awk}) to refer to an element of a two-dimensional array named @code{grid} is with @code{grid[@var{x},@var{y}]}. @@ -16460,8 +16611,9 @@ a[1][3][1, "name"] = "barney" Each subarray and the main array can be of different length. In fact, the elements of an array or its subarray do not all have to have the same type. This means that the main array and any of its subarrays can be -non-rectangular, or jagged in structure. One can assign a scalar value to -the index @code{4} of the main array @code{a}: +non-rectangular, or jagged in structure. You can assign a scalar value to +the index @code{4} of the main array @code{a}, even though @code{a[1]} +is itself an array and not a scalar: @example a[4] = "An element in a jagged array" @@ -16543,6 +16695,8 @@ for (i in array) @{ print array[i][j] @} @} + else + print array[i] @} @end example @@ -16827,8 +16981,9 @@ Often random integers are needed instead. Following is a user-defined function that can be used to obtain a random non-negative integer less than @var{n}: @example -function randint(n) @{ - return int(n * rand()) +function randint(n) +@{ + return int(n * rand()) @} @end example @@ -16848,8 +17003,7 @@ function roll(n) @{ return 1 + int(rand() * n) @} # Roll 3 six-sided dice and # print total number of points. @{ - printf("%d points\n", - roll(6)+roll(6)+roll(6)) + printf("%d points\n", roll(6) + roll(6) + roll(6)) @} @end example @@ -16938,7 +17092,7 @@ doing index calculations, particularly if you are used to C. In the following list, optional parameters are enclosed in square brackets@w{ ([ ]).} Several functions perform string substitution; the full discussion is provided in the description of the @code{sub()} function, which comes -towards the end since the list is presented in alphabetic order. +towards the end since the list is presented alphabetically. Those functions that are specific to @command{gawk} are marked with a pound sign (@samp{#}). They are not available in compatibility mode @@ -16982,6 +17136,7 @@ When comparing strings, @code{IGNORECASE} affects the sorting (@pxref{Array Sorting Functions}). If the @var{source} array contains subarrays as values (@pxref{Arrays of Arrays}), they will come last, after all scalar values. +Subarrays are @emph{not} recursively sorted. For example, if the contents of @code{a} are as follows: @@ -17118,7 +17273,11 @@ $ @kbd{awk 'BEGIN @{ print index("peanut", "an") @}'} @noindent If @var{find} is not found, @code{index()} returns zero. -It is a fatal error to use a regexp constant for @var{find}. +@cindex dark corner, regexp as second argument to @code{index()} +With BWK @command{awk} and @command{gawk}, +it is a fatal error to use a regexp constant for @var{find}. +Other implementations allow it, simply treating the regexp +constant as an expression meaning @samp{$0 ~ /regexp/}. @value{DARKCORNER}. @item @code{length(}[@var{string}]@code{)} @cindexawkfunc{length} @@ -17222,8 +17381,8 @@ for @code{match()}, the order is the same as for the @samp{~} operator: @cindex @code{RSTART} variable, @code{match()} function and @cindex @code{RLENGTH} variable, @code{match()} function and @cindex @code{match()} function, @code{RSTART}/@code{RLENGTH} variables -The @code{match()} function sets the built-in variable @code{RSTART} to -the index. It also sets the built-in variable @code{RLENGTH} to the +The @code{match()} function sets the predefined variable @code{RSTART} to +the index. It also sets the predefined variable @code{RLENGTH} to the length in characters of the matched substring. If no match is found, @code{RSTART} is set to zero, and @code{RLENGTH} to @minus{}1. @@ -17232,13 +17391,12 @@ For example: @example @c file eg/misc/findpat.awk @{ - if ($1 == "FIND") - regex = $2 - else @{ - where = match($0, regex) - if (where != 0) - print "Match of", regex, "found at", - where, "in", $0 + if ($1 == "FIND") + regex = $2 + else @{ + where = match($0, regex) + if (where != 0) + print "Match of", regex, "found at", where, "in", $0 @} @} @c endfile @@ -17334,7 +17492,7 @@ Any leading separator will be in @code{@var{seps}[0]}. The @code{patsplit()} function splits strings into pieces in a manner similar to the way input lines are split into fields using @code{FPAT} -(@pxref{Splitting By Content}. +(@pxref{Splitting By Content}). Before splitting the string, @code{patsplit()} deletes any previously existing elements in the arrays @var{array} and @var{seps}. @@ -17347,8 +17505,7 @@ and store the pieces in @var{array} and the separator strings in the @code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so forth. The string value of the third argument, @var{fieldsep}, is a regexp describing where to split @var{string} (much as @code{FS} can -be a regexp describing where to split input records; -@pxref{Regexp Field Splitting}). +be a regexp describing where to split input records). If @var{fieldsep} is omitted, the value of @code{FS} is used. @code{split()} returns the number of elements created. @var{seps} is a @command{gawk} extension with @code{@var{seps}[@var{i}]} @@ -17643,6 +17800,59 @@ Nonalphabetic characters are left unchanged. For example, @code{toupper("MiXeD cAsE 123")} returns @code{"MIXED CASE 123"}. @end table +@cindex sidebar, Matching the Null String +@ifdocbook +@docbook +<sidebar><title>Matching the Null String</title> +@end docbook + +@cindex matching, null strings +@cindex null strings, matching +@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching +@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching + +In @command{awk}, the @samp{*} operator can match the null string. +This is particularly important for the @code{sub()}, @code{gsub()}, +and @code{gensub()} functions. For example: + +@example +$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} +@print{} XaXbXcX +@end example + +@noindent +Although this makes a certain amount of sense, it can be surprising. + +@docbook +</sidebar> +@end docbook +@end ifdocbook + +@ifnotdocbook +@cartouche +@center @b{Matching the Null String} + + +@cindex matching, null strings +@cindex null strings, matching +@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching +@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching + +In @command{awk}, the @samp{*} operator can match the null string. +This is particularly important for the @code{sub()}, @code{gsub()}, +and @code{gensub()} functions. For example: + +@example +$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} +@print{} XaXbXcX +@end example + +@noindent +Although this makes a certain amount of sense, it can be surprising. +@end cartouche +@end ifnotdocbook + + @node Gory Details @subsubsection More About @samp{\} and @samp{&} with @code{sub()}, @code{gsub()}, and @code{gensub()} @@ -17656,7 +17866,7 @@ Nonalphabetic characters are left unchanged. For example, @cindex ampersand (@code{&}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @quotation CAUTION -This section has been known to cause headaches. +This subsubsection has been reported to cause headaches. You might want to skip it upon first reading. @end quotation @@ -17947,58 +18157,6 @@ and the special cases for @code{sub()} and @code{gsub()}, we recommend the use of @command{gawk} and @code{gensub()} when you have to do substitutions. -@cindex sidebar, Matching the Null String -@ifdocbook -@docbook -<sidebar><title>Matching the Null String</title> -@end docbook - -@cindex matching, null strings -@cindex null strings, matching -@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching -@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching - -In @command{awk}, the @samp{*} operator can match the null string. -This is particularly important for the @code{sub()}, @code{gsub()}, -and @code{gensub()} functions. For example: - -@example -$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} -@print{} XaXbXcX -@end example - -@noindent -Although this makes a certain amount of sense, it can be surprising. - -@docbook -</sidebar> -@end docbook -@end ifdocbook - -@ifnotdocbook -@cartouche -@center @b{Matching the Null String} - - -@cindex matching, null strings -@cindex null strings, matching -@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching -@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching - -In @command{awk}, the @samp{*} operator can match the null string. -This is particularly important for the @code{sub()}, @code{gsub()}, -and @code{gensub()} functions. For example: - -@example -$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} -@print{} XaXbXcX -@end example - -@noindent -Although this makes a certain amount of sense, it can be surprising. -@end cartouche -@end ifnotdocbook - @node I/O Functions @subsection Input/Output Functions @cindex input/output functions @@ -18051,10 +18209,9 @@ buffers its output and the @code{fflush()} function forces @cindex extensions, common@comma{} @code{fflush()} function @cindex Brian Kernighan's @command{awk} -@code{fflush()} was added to BWK @command{awk} in -April of 1992. For two decades, it was not part of the POSIX standard. -As of December, 2012, it was accepted for inclusion into the POSIX -standard. +Brian Kernighan added @code{fflush()} to his @command{awk} in April +of 1992. For two decades, it was a common extension. In December, +2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=634, the Austin Group website}. POSIX standardizes @code{fflush()} as follows: If there @@ -18451,7 +18608,7 @@ is out of range, @code{mktime()} returns @minus{}1. @cindex @command{gawk}, @code{PROCINFO} array in @cindex @code{PROCINFO} array -@item @code{strftime(} [@var{format} [@code{,} @var{timestamp} [@code{,} @var{utc-flag}] ] ]@code{)} +@item @code{strftime(}[@var{format} [@code{,} @var{timestamp} [@code{,} @var{utc-flag}] ] ]@code{)} @c STARTOFRANGE strf @cindexgawkfunc{strftime} @cindex format time string @@ -18557,7 +18714,7 @@ of its ISO week number is 2013, even though its year is 2012. The full year of the ISO week number, as a decimal number. @item %h -Equivalent to @samp{%b}. +Equivalent to @code{%b}. @item %H The hour (24-hour clock) as a decimal number (00--23). @@ -18626,7 +18783,7 @@ The locale's ``appropriate'' date representation. @item %X The locale's ``appropriate'' time representation. -(This is @samp{%T} in the @code{"C"} locale.) +(This is @code{%T} in the @code{"C"} locale.) @item %y The year modulo 100 as a decimal number (00--99). @@ -18647,7 +18804,7 @@ no time zone is determinable. @item %Ec %EC %Ex %EX %Ey %EY %Od %Oe %OH @itemx %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy ``Alternate representations'' for the specifications -that use only the second letter (@samp{%c}, @samp{%C}, +that use only the second letter (@code{%c}, @code{%C}, and so on).@footnote{If you don't understand any of this, don't worry about it; these facilities are meant to make it easier to ``internationalize'' programs. @@ -18718,7 +18875,7 @@ the string. For example: @example $ date '+Today is %A, %B %d, %Y.' -@print{} Today is Monday, May 05, 2014. +@print{} Today is Monday, September 22, 2014. @end example Here is the @command{gawk} version of the @command{date} utility. @@ -18910,19 +19067,18 @@ For example, if you have a bit string @samp{10111001} and you shift it right by three bits, you end up with @samp{00010111}.@footnote{This example shows that 0's come in on the left side. For @command{gawk}, this is always true, but in some languages, it's possible to have the left side -fill with 1's. Caveat emptor.} +fill with 1's.} @c Purposely decided to use 0's and 1's here. 2/2001. -If you start over -again with @samp{10111001} and shift it left by three bits, you end up -with @samp{11001000}. -@command{gawk} provides built-in functions that implement the -bitwise operations just described. They are: +If you start over again with @samp{10111001} and shift it left by three +bits, you end up with @samp{11001000}. The following list describes +@command{gawk}'s built-in functions that implement the bitwise operations. +Optional parameters are enclosed in square brackets ([ ]): @cindex @command{gawk}, bitwise operations in @table @code @cindexgawkfunc{and} @cindex bitwise AND -@item @code{and(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{and(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise AND of the arguments. There must be at least two. @cindexgawkfunc{compl} @@ -18937,7 +19093,7 @@ Return the value of @var{val}, shifted left by @var{count} bits. @cindexgawkfunc{or} @cindex bitwise OR -@item @code{or(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{or(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise OR of the arguments. There must be at least two. @cindexgawkfunc{rshift} @@ -18947,7 +19103,7 @@ Return the value of @var{val}, shifted right by @var{count} bits. @cindexgawkfunc{xor} @cindex bitwise XOR -@item @code{xor(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{xor(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise XOR of the arguments. There must be at least two. @end table @@ -19070,7 +19226,7 @@ results of the @code{compl()}, @code{lshift()}, and @code{rshift()} functions. @command{gawk} provides a single function that lets you distinguish an array from a scalar variable. This is necessary for writing code -that traverses every element of an array of arrays. +that traverses every element of an array of arrays (@pxref{Arrays of Arrays}). @table @code @@ -19086,12 +19242,14 @@ an array or not. The second is inside the body of a user-defined function (not discussed yet; @pxref{User-defined}), to test if a parameter is an array or not. -Note, however, that using @code{isarray()} at the global level to test +@quotation NOTE +Using @code{isarray()} at the global level to test variables makes no sense. Since you are the one writing the program, you are supposed to know if your variables are arrays or not. And in fact, due to the way @command{gawk} works, if you pass the name of a variable that has not been previously used to @code{isarray()}, @command{gawk} -will end up turning it into a scalar. +ends up turning it into a scalar. +@end quotation @node I18N Functions @subsection String-Translation Functions @@ -19213,7 +19371,7 @@ the call. A function cannot have two parameters with the same name, nor may it have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters -cannot have the same name as one of the special built-in variables +cannot have the same name as one of the special predefined variables (@pxref{Built-in Variables}). Not all versions of @command{awk} enforce this restriction. @@ -19352,7 +19510,7 @@ extra whitespace signifies the start of the local variable list): function delarray(a, i) @{ for (i in a) - delete a[i] + delete a[i] @} @end example @@ -19363,7 +19521,7 @@ Instead of having to repeat this loop everywhere that you need to clear out an array, your program can just call @code{delarray}. (This guarantees portability. The use of @samp{delete @var{array}} to delete -the contents of an entire array is a recent@footnote{Late in 2012.} +the contents of an entire array is a relatively recent@footnote{Late in 2012.} addition to the POSIX standard.) The following is an example of a recursive function. It takes a string @@ -19393,7 +19551,7 @@ $ @kbd{echo "Don't Panic!" |} @print{} !cinaP t'noD @end example -The C @code{ctime()} function takes a timestamp and returns it in a string, +The C @code{ctime()} function takes a timestamp and returns it as a string, formatted in a well-known fashion. The following example uses the built-in @code{strftime()} function (@pxref{Time Functions}) @@ -19408,13 +19566,19 @@ to create an @command{awk} version of @code{ctime()}: function ctime(ts, format) @{ - format = PROCINFO["strftime"] + format = "%a %b %e %H:%M:%S %Z %Y" + if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) @} @c endfile @end example + +You might think that @code{ctime()} could use @code{PROCINFO["strftime"]} +for its format string. That would be a mistake, since @code{ctime()} is +supposed to return the time formatted in a standard fashion, and user-level +code could have changed @code{PROCINFO["strftime"]}. @c ENDOFRANGE fdef @node Function Caveats @@ -19986,7 +20150,7 @@ saving it in @code{start}. The last part of the code loops through each function name (from @code{$2} up to the marker, @samp{data:}), calling the function named by the field. The indirect function call itself occurs as a parameter in the call to @code{printf}. -(The @code{printf} format string uses @samp{%s} as the format specifier so that we +(The @code{printf} format string uses @code{%s} as the format specifier so that we can use functions that return strings, as well as numbers. Note that the result from the indirect call is concatenated with the empty string, in order to force it to be a string value.) @@ -20063,7 +20227,7 @@ function quicksort(data, left, right, less_than, i, last) # quicksort_swap --- helper function for quicksort, should really be inline -function quicksort_swap(data, i, j, temp) +function quicksort_swap(data, i, j, temp) @{ temp = data[i] data[i] = data[j] @@ -20184,6 +20348,69 @@ $ @kbd{gawk -f quicksort.awk -f indirectcall.awk class_data2} @print{} rsort: <100.0 95.6 93.4 87.1> @end example +Another example where indirect functions calls are useful can be found in +processing arrays. @DBREF{Walking Arrays} presented a simple function +for ``walking'' an array of arrays. That function simply printed the +name and value of each scalar array element. However, it is easy to +generalize that function, by passing in the name of a function to call +when walking an array. The modified function looks like this: + +@example +@c file eg/lib/processarray.awk +function process_array(arr, name, process, do_arrays, i, new_name) +@{ + for (i in arr) @{ + new_name = (name "[" i "]") + if (isarray(arr[i])) @{ + if (do_arrays) + @@process(new_name, arr[i]) + process_array(arr[i], new_name, process, do_arrays) + @} else + @@process(new_name, arr[i]) + @} +@} +@c endfile +@end example + +The arguments are as follows: + +@table @code +@item arr +The array. + +@item name +The name of the array (a string). + +@item process +The name of the function to call. + +@item do_arrays +If this is true, the function can handle elements that are subarrays. +@end table + +If subarrays are to be processed, that is done before walking them further. + +When run with the following scaffolding, the function produces the same +results as does the earlier @code{walk_array()} function: + +@example +BEGIN @{ + a[1] = 1 + a[2][1] = 21 + a[2][2] = 22 + a[3] = 3 + a[4][1][1] = 411 + a[4][2] = 42 + + process_array(a, "a", "do_print", 0) +@} + +function do_print(name, element) +@{ + printf "%s = %s\n", name, element +@} +@end example + Remember that you must supply a leading @samp{@@} in front of an indirect function call. Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function @@ -20214,10 +20441,11 @@ functions. @item POSIX @command{awk} provides three kinds of built-in functions: numeric, -string, and I/O. @command{gawk} provides functions that work with values -representing time, do bit manipulation, sort arrays, and internationalize -and localize programs. @command{gawk} also provides several extensions to -some of standard functions, typically in the form of additional arguments. +string, and I/O. @command{gawk} provides functions that sort arrays, work +with values representing time, do bit manipulation, determine variable +type (array vs.@: scalar), and internationalize and localize programs. +@command{gawk} also provides several extensions to some of standard +functions, typically in the form of additional arguments. @item Functions accept zero or more arguments and return a value. The @@ -20454,7 +20682,7 @@ example, @code{getopt()}'s @code{Opterr} and @code{Optind} variables (@pxref{Getopt Function}). The leading capital letter indicates that it is global, while the fact that the variable name is not all capital letters indicates that the variable is -not one of @command{awk}'s built-in variables, such as @code{FS}. +not one of @command{awk}'s predefined variables, such as @code{FS}. @cindex @option{--dump-variables} option, using for library functions It is also important that @emph{all} variables in library @@ -20468,8 +20696,9 @@ are very difficult to track down: function lib_func(x, y, l1, l2) @{ @dots{} - @var{use variable} some_var # some_var should be local - @dots{} # but is not by oversight + # some_var should be local but by oversight is not + @var{use variable} some_var + @dots{} @} @end example @@ -20510,6 +20739,7 @@ programming use. * Join Function:: A function to join an array into a string. * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the shell. @end menu @node Strtonum Function @@ -20580,7 +20810,7 @@ function mystrtonum(str, ret, n, i, k, c) # a[5] = "123.45" # a[6] = "1.e3" # a[7] = "1.32" -# a[7] = "1.32E2" +# a[8] = "1.32E2" # # for (i = 1; i in a; i++) # print a[i], strtonum(a[i]), mystrtonum(a[i]) @@ -20591,9 +20821,12 @@ function mystrtonum(str, ret, n, i, k, c) The function first looks for C-style octal numbers (base 8). If the input string matches a regular expression describing octal numbers, then @code{mystrtonum()} loops through each character in the -string. It sets @code{k} to the index in @code{"01234567"} of the current -octal digit. Since the return value is one-based, the @samp{k--} -adjusts @code{k} so it can be used in computing the return value. +string. It sets @code{k} to the index in @code{"1234567"} of the current +octal digit. +The return value will either be the same number as the digit, or zero +if the character is not there, which will be true for a @samp{0}. +This is safe, since the regexp test in the @code{if} ensures that +only octal values are converted. Similar logic applies to the code that checks for and converts a hexadecimal value, which starts with @samp{0x} or @samp{0X}. @@ -20626,7 +20859,7 @@ that a condition or set of conditions is true. Before proceeding with a particular computation, you make a statement about what you believe to be the case. Such a statement is known as an @dfn{assertion}. The C language provides an @code{<assert.h>} header file -and corresponding @code{assert()} macro that the programmer can use to make +and corresponding @code{assert()} macro that a programmer can use to make assertions. If an assertion fails, the @code{assert()} macro arranges to print a diagnostic message describing the condition that should have been true but was not, and then it kills the program. In C, using @@ -21096,7 +21329,7 @@ function getlocaltime(time, ret, now, i) now = systime() # return date(1)-style output - ret = strftime(PROCINFO["strftime"], now) + ret = strftime("%a %b %e %H:%M:%S %Z %Y", now) # clear out target array delete time @@ -21211,6 +21444,87 @@ if (length(contents) == 0) This tests the result to see if it is empty or not. An equivalent test would be @samp{contents == ""}. +@xref{Extension Sample Readfile}, for an extension function that +also reads an entire file into memory. + +@node Shell Quoting +@subsection Quoting Strings to Pass to The Shell + +@c included by permission +@ignore +Date: Sun, 27 Jul 2014 17:16:16 -0700 +Message-ID: <CAKuGj+iCF_obaCLDUX60aSAgbfocFVtguG39GyeoNxTFby5sqQ@mail.gmail.com> +Subject: Useful awk function +From: Mike Brennan <mike@madronabluff.com> +To: Arnold Robbins <arnold@skeeve.com> +@end ignore + +Michael Brennan offers the following programming pattern, +which he uses frequently: + +@example +#! /bin/sh + +awkp=' + @dots{} + ' + +@var{input_program} | awk "$awkp" | /bin/sh +@end example + +For example, a program of his named @command{flac-edit} has this form: + +@example +$ @kbd{flac-edit -song="Whoope! That's Great" file.flac} +@end example + +It generates the following output, which is to be piped to +the shell (@file{/bin/sh}): + +@example +chmod +w file.flac +metaflac --remove-tag=TITLE file.flac +LANG=en_US.88591 metaflac --set-tag=TITLE='Whoope! That'"'"'s Great' file.flac +chmod -w file.flac +@end example + +Note the need for shell quoting. The function @code{shell_quote()} +does it. @code{SINGLE} is the one-character string @code{"'"} and +@code{QSINGLE} is the three-character string @code{"\"'\""}. + +@example +@c file eg/lib/shellquote.awk +# shell_quote --- quote an argument for passing to the shell +@c endfile +@ignore +@c file eg/lib/shellquote.awk +# +# Michael Brennan +# brennan@@madronabluff.com +# September 2014 +@c endfile +@end ignore +@c file eg/lib/shellquote.awk + +function shell_quote(s, # parameter + SINGLE, QSINGLE, i, X, n, ret) # locals +@{ + if (s == "") + return "\"\"" + + SINGLE = "\x27" # single quote + QSINGLE = "\"\x27\"" + n = split(s, X, SINGLE) + + ret = SINGLE X[1] SINGLE + for (i = 2; i <= n; i++) + ret = ret QSINGLE SINGLE X[i] SINGLE + + return ret +@} +@c endfile +@end example + @node Data File Management @section @value{DDF} Management @@ -21268,15 +21582,14 @@ Besides solving the problem in only nine(!) lines of code, it does so @c # Arnold Robbins, arnold@@skeeve.com, Public Domain @c # January 1992 -FILENAME != _oldfilename \ -@{ +FILENAME != _oldfilename @{ if (_oldfilename != "") endfile(_oldfilename) _oldfilename = FILENAME beginfile(FILENAME) @} -END @{ endfile(FILENAME) @} +END @{ endfile(FILENAME) @} @end example This file must be loaded before the user's ``main'' program, so that the @@ -21329,7 +21642,7 @@ FNR == 1 @{ beginfile(FILENAME) @} -END @{ endfile(_filename_) @} +END @{ endfile(_filename_) @} @c endfile @end example @@ -21428,24 +21741,12 @@ function rewind( i) @c endfile @end example -This code relies on the @code{ARGIND} variable -(@pxref{Auto-set}), -which is specific to @command{gawk}. -If you are not using -@command{gawk}, you can use ideas presented in -@ifnotinfo -the previous @value{SECTION} -@end ifnotinfo -@ifinfo -@ref{Filetrans Function}, -@end ifinfo -to either update @code{ARGIND} on your own -or modify this code as appropriate. - -The @code{rewind()} function also relies on the @code{nextfile} keyword -(@pxref{Nextfile Statement}). Because of this, you should not call it -from an @code{ENDFILE} rule. (This isn't necessary anyway, since as soon -as an @code{ENDFILE} rule finishes @command{gawk} goes to the next file!) +The @code{rewind()} function relies on the @code{ARGIND} variable +(@pxref{Auto-set}), which is specific to @command{gawk}. It also +relies on the @code{nextfile} keyword (@pxref{Nextfile Statement}). +Because of this, you should not call it from an @code{ENDFILE} rule. +(This isn't necessary anyway, since as soon as an @code{ENDFILE} rule +finishes @command{gawk} goes to the next file!) @node File Checking @subsection Checking for Readable @value{DDF}s @@ -21478,7 +21779,7 @@ the following program to your @command{awk} program: BEGIN @{ for (i = 1; i < ARGC; i++) @{ - if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/ \ + if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \ || ARGV[i] == "-" || ARGV[i] == "/dev/stdin") continue # assignment or standard input else if ((getline junk < ARGV[i]) < 0) # unreadable @@ -21496,6 +21797,11 @@ Removing the element from @code{ARGV} with @code{delete} skips the file (since it's no longer in the list). See also @ref{ARGC and ARGV}. +The regular expression check purposely does not use character classes +such as @samp{[:alpha:]} and @samp{[:alnum:]} +(@pxref{Bracket Expressions}) +since @command{awk} variable names only allow the English letters. + @node Empty Files @subsection Checking for Zero-length Files @@ -21592,7 +21898,7 @@ a library file does the trick: function disable_assigns(argc, argv, i) @{ for (i = 1; i < argc; i++) - if (argv[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/) + if (argv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/) argv[i] = ("./" argv[i]) @} @@ -21964,12 +22270,18 @@ In both runs, the first @option{--} terminates the arguments to etc., as its own options. @quotation NOTE -After @code{getopt()} is through, it is the responsibility of the -user level code to clear out all the elements of @code{ARGV} from 1 +After @code{getopt()} is through, +user level code must clear out all the elements of @code{ARGV} from 1 to @code{Optind}, so that @command{awk} does not try to process the command-line options as @value{FN}s. @end quotation +Using @samp{#!} with the @option{-E} option may help avoid +conflicts between your program's options and @command{gawk}'s options, +since @option{-E} causes @command{gawk} to abandon processing of +further options +(@pxref{Executable Scripts}, and @pxref{Options}). + Several of the sample programs presented in @ref{Sample Programs}, use @code{getopt()} to process their arguments. @@ -22214,13 +22526,14 @@ The @code{BEGIN} rule sets a private variable to the directory where routine, we have chosen to put it in @file{/usr/local/libexec/awk}; however, you might want it to be in a different directory on your system. -The function @code{_pw_init()} keeps three copies of the user information -in three associative arrays. The arrays are indexed by username +The function @code{_pw_init()} fills three copies of the user information +into three associative arrays. The arrays are indexed by username (@code{_pw_byname}), by user ID number (@code{_pw_byuid}), and by order of occurrence (@code{_pw_bycount}). The variable @code{_pw_inited} is used for efficiency, since @code{_pw_init()} needs to be called only once. +@cindex @code{PROCINFO} array, testing the field splitting @cindex @code{getline} command, @code{_pw_init()} function Because this function uses @code{getline} to read information from @command{pwcat}, it first saves the values of @code{FS}, @code{RS}, and @code{$0}. @@ -22228,13 +22541,8 @@ It notes in the variable @code{using_fw} whether field splitting with @code{FIELDWIDTHS} is in effect or not. Doing so is necessary, since these functions could be called from anywhere within a user's program, and the user may have his -or her -own way of splitting records and fields. - -@cindex @code{PROCINFO} array, testing the field splitting -The @code{using_fw} variable checks @code{PROCINFO["FS"]}, which -is @code{"FIELDWIDTHS"} if field splitting is being done with -@code{FIELDWIDTHS}. This makes it possible to restore the correct +or her own way of splitting records and fields. +This makes it possible to restore the correct field-splitting mechanism later. The test can only be true for @command{gawk}. It is false if using @code{FS} or @code{FPAT}, or on some other @command{awk} implementation. @@ -22548,8 +22856,7 @@ function _gr_init( oldfs, oldrs, olddol0, grcat, n = split($4, a, "[ \t]*,[ \t]*") for (i = 1; i <= n; i++) if (a[i] in _gr_groupsbyuser) - _gr_groupsbyuser[a[i]] = \ - _gr_groupsbyuser[a[i]] " " $1 + _gr_groupsbyuser[a[i]] = gr_groupsbyuser[a[i]] " " $1 else _gr_groupsbyuser[a[i]] = $1 @@ -22757,12 +23064,12 @@ When run, the program produces the following output: @example $ @kbd{gawk -f walk_array.awk} -@print{} a[4][1][1] = 411 -@print{} a[4][2] = 42 @print{} a[1] = 1 @print{} a[2][1] = 21 @print{} a[2][2] = 22 @print{} a[3] = 3 +@print{} a[4][1][1] = 411 +@print{} a[4][2] = 42 @end example @c ENDOFRANGE libfgdata @@ -22776,8 +23083,8 @@ $ @kbd{gawk -f walk_array.awk} @itemize @value{BULLET} @item Reading programs is an excellent way to learn Good Programming. -The functions provided in this @value{CHAPTER} and the next are intended -to serve that purpose. +The functions and programs provided in this @value{CHAPTER} and the next +are intended to serve that purpose. @item When writing general-purpose library functions, put some thought into how @@ -23064,22 +23371,16 @@ supplied: # Requires getopt() and join() library functions @group -function usage( e1, e2) +function usage() @{ - e1 = "usage: cut [-f list] [-d c] [-s] [files...]" - e2 = "usage: cut [-c list] [files...]" - print e1 > "/dev/stderr" - print e2 > "/dev/stderr" + print("usage: cut [-f list] [-d c] [-s] [files...]") > "/dev/stderr" + print("usage: cut [-c list] [files...]") > "/dev/stderr" exit 1 @} @end group @c endfile @end example -@noindent -The variables @code{e1} and @code{e2} are used so that the function -fits nicely on the @value{PAGE}. - @cindex @code{BEGIN} pattern, running @command{awk} programs and @cindex @code{FS} variable, running @command{awk} programs and Next comes a @code{BEGIN} rule that parses the command-line options. @@ -23374,7 +23675,7 @@ and the file transition library program The program begins with a descriptive comment and then a @code{BEGIN} rule that processes the command-line arguments with @code{getopt()}. The @option{-i} (ignore case) option is particularly easy with @command{gawk}; we just use the -@code{IGNORECASE} built-in variable +@code{IGNORECASE} predefined variable (@pxref{Built-in Variables}): @cindex @code{egrep.awk} program @@ -23580,19 +23881,15 @@ and then exits: @example @c file eg/prog/egrep.awk -function usage( e) +function usage() @{ - e = "Usage: egrep [-csvil] [-e pat] [files ...]" - e = e "\n\tegrep [-csvil] pat [files ...]" - print e > "/dev/stderr" + print("Usage: egrep [-csvil] [-e pat] [files ...]") > "/dev/stderr" + print("\n\tegrep [-csvil] pat [files ...]") > "/dev/stderr" exit 1 @} @c endfile @end example -The variable @code{e} is used so that the function fits nicely -on the printed page. - @c ENDOFRANGE regexps @c ENDOFRANGE sfregexp @c ENDOFRANGE fsregexp @@ -23650,6 +23947,7 @@ numbers: # May 1993 # Revised February 1996 # Revised May 2014 +# Revised September 2014 @c endfile @end ignore @@ -23668,26 +23966,22 @@ BEGIN @{ printf("uid=%d", uid) pw = getpwuid(uid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (euid != uid) @{ printf(" euid=%d", euid) pw = getpwuid(euid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) @} printf(" gid=%d", gid) pw = getgrgid(gid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (egid != gid) @{ printf(" egid=%d", egid) pw = getgrgid(egid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) @} for (i = 1; ("group" i) in PROCINFO; i++) @{ @@ -23696,8 +23990,7 @@ BEGIN @{ group = PROCINFO["group" i] printf("%d", group) pw = getgrgid(group) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (("group" (i+1)) in PROCINFO) printf(",") @} @@ -23707,8 +24000,10 @@ BEGIN @{ function pr_first_field(str, a) @{ - split(str, a, ":") - printf("(%s)", a[1]) + if (str != "") @{ + split(str, a, ":") + printf("(%s)", a[1]) + @} @} @c endfile @end example @@ -23731,7 +24026,8 @@ tested, and the loop body never executes. The @code{pr_first_field()} function simply isolates out some code that is used repeatedly, making the whole program -slightly shorter and cleaner. +shorter and cleaner. In particular, moving the check for +the empty string into this function saves several lines of code. @c ENDOFRANGE id @@ -23858,19 +24154,14 @@ The @code{usage()} function simply prints an error message and exits: @example @c file eg/prog/split.awk -function usage( e) +function usage() @{ - e = "usage: split [-num] [file] [outname]" - print e > "/dev/stderr" + print("usage: split [-num] [file] [outname]") > "/dev/stderr" exit 1 @} @c endfile @end example -@noindent -The variable @code{e} is used so that the function -fits nicely on the @value{PAGE}. - This program is a bit sloppy; it relies on @command{awk} to automatically close the last file instead of doing it in an @code{END} rule. It also assumes that letters are contiguous in the character set, @@ -24029,10 +24320,10 @@ The options for @command{uniq} are: @table @code @item -d -Print only repeated lines. +Print only repeated (duplicated) lines. @item -u -Print only nonrepeated lines. +Print only nonrepeated (unique) lines. @item -c Count lines. This option overrides @option{-d} and @option{-u}. Both repeated @@ -24101,10 +24392,9 @@ standard output, @file{/dev/stdout}: @end ignore @c file eg/prog/uniq.awk -function usage( e) +function usage() @{ - e = "Usage: uniq [-udc [-n]] [+n] [ in [ out ]]" - print e > "/dev/stderr" + print("Usage: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr" exit 1 @} @@ -24158,22 +24448,20 @@ BEGIN @{ @end example The following function, @code{are_equal()}, compares the current line, -@code{$0}, to the -previous line, @code{last}. It handles skipping fields and characters. -If no field count and no character count are specified, @code{are_equal()} -simply returns one or zero depending upon the result of a simple string -comparison of @code{last} and @code{$0}. Otherwise, things get more -complicated. -If fields have to be skipped, each line is broken into an array using -@code{split()} -(@pxref{String Functions}); -the desired fields are then joined back into a line using @code{join()}. -The joined lines are stored in @code{clast} and @code{cline}. -If no fields are skipped, @code{clast} and @code{cline} are set to -@code{last} and @code{$0}, respectively. -Finally, if characters are skipped, @code{substr()} is used to strip off the -leading @code{charcount} characters in @code{clast} and @code{cline}. The -two strings are then compared and @code{are_equal()} returns the result: +@code{$0}, to the previous line, @code{last}. It handles skipping fields +and characters. If no field count and no character count are specified, +@code{are_equal()} returns one or zero depending upon the result of a +simple string comparison of @code{last} and @code{$0}. + +Otherwise, things get more complicated. If fields have to be skipped, +each line is broken into an array using @code{split()} (@pxref{String +Functions}); the desired fields are then joined back into a line +using @code{join()}. The joined lines are stored in @code{clast} and +@code{cline}. If no fields are skipped, @code{clast} and @code{cline} +are set to @code{last} and @code{$0}, respectively. Finally, if +characters are skipped, @code{substr()} is used to strip off the leading +@code{charcount} characters in @code{clast} and @code{cline}. The two +strings are then compared and @code{are_equal()} returns the result: @example @c file eg/prog/uniq.awk @@ -24264,6 +24552,13 @@ END @{ @c endfile @end example +@c FIXME: Include this? +@ignore +This program does not follow our recommended convention of naming +global variables with a leading capital letter. Doing that would +make the program a little easier to follow. +@end ignore + @ifset FOR_PRINT The logic for choosing which lines to print represents a @dfn{state machine}, which is ``a device that can be in one of a set number of stable @@ -24271,7 +24566,7 @@ conditions depending on its previous condition and on the present values of its inputs.''@footnote{This is the definition returned from entering @code{define: state machine} into Google.} Brian Kernighan suggests that -``an alternative approach to state mechines is to just read +``an alternative approach to state machines is to just read the input into an array, then use indexing. It's almost always easier code, and for most inputs where you would use this, just as fast.'' Consider how to rewrite the logic to follow this @@ -24309,7 +24604,7 @@ one or more input files. Its usage is as follows: If no files are specified on the command line, @command{wc} reads its standard input. If there are multiple files, it also prints total counts for all -the files. The options and their meanings are shown in the following list: +the files. The options and their meanings are as follows: @table @code @item -l @@ -24790,8 +25085,8 @@ character of the ``to'' list is used for the remaining characters in the Once upon a time, @c early or mid-1989! -a user proposed that a transliteration function should -be added to @command{gawk}. +a user proposed adding a transliteration function +to @command{gawk}. @c Wishing to avoid gratuitous new features, @c at least theoretically The following program was written to @@ -24799,15 +25094,12 @@ prove that character transliteration could be done with a user-level function. This program is not as complete as the system @command{tr} utility but it does most of the job. -The @command{translate} program demonstrates one of the few weaknesses -of standard @command{awk}: dealing with individual characters is very -painful, requiring repeated use of the @code{substr()}, @code{index()}, -and @code{gsub()} built-in functions -(@pxref{String Functions}).@footnote{This -program was also written before @command{gawk} acquired the ability to -split each character in a string into separate array elements.} -There are two functions. The first, @code{stranslate()}, takes three -arguments: +The @command{translate} program was written long before @command{gawk} +acquired the ability to split each character in a string into separate +array elements. Thus, it makes repeated use of the @code{substr()}, +@code{index()}, and @code{gsub()} built-in functions (@pxref{String +Functions}). There are two functions. The first, @code{stranslate()}, +takes three arguments: @table @code @item from @@ -24826,7 +25118,7 @@ loop goes through @code{from}, one character at a time. For each character in @code{from}, if the character appears in @code{target}, it is replaced with the corresponding @code{to} character. -The @code{translate()} function simply calls @code{stranslate()} using @code{$0} +The @code{translate()} function calls @code{stranslate()} using @code{$0} as the target. The main program sets two global variables, @code{FROM} and @code{TO}, from the command line, and then changes @code{ARGV} so that @command{awk} reads from the standard input. @@ -24961,7 +25253,7 @@ of lines on the page Most of the work is done in the @code{printpage()} function. The label lines are stored sequentially in the @code{line} array. But they have to print horizontally; @code{line[1]} next to @code{line[6]}, -@code{line[2]} next to @code{line[7]}, and so on. Two loops are used to +@code{line[2]} next to @code{line[7]}, and so on. Two loops accomplish this. The outer loop, controlled by @code{i}, steps through every 10 lines of data; this is each row of labels. The inner loop, controlled by @code{j}, goes through the lines within the row. @@ -25075,7 +25367,7 @@ in a useful format. At first glance, a program like this would seem to do the job: @example -# Print list of word frequencies +# wordfreq-first-try.awk --- print list of word frequencies @{ for (i = 1; i <= NF; i++) @@ -25292,16 +25584,16 @@ Texinfo input file into separate files. This @value{DOCUMENT} is written in @uref{http://www.gnu.org/software/texinfo/, Texinfo}, the GNU project's document formatting language. A single Texinfo source file can be used to produce both -printed and online documentation. +printed documentation, with @TeX{}, and online documentation. @ifnotinfo -Texinfo is fully documented in the book +(Texinfo is fully documented in the book @cite{Texinfo---The GNU Documentation Format}, available from the Free Software Foundation, -and also available @uref{http://www.gnu.org/software/texinfo/manual/texinfo/, online}. +and also available @uref{http://www.gnu.org/software/texinfo/manual/texinfo/, online}.) @end ifnotinfo @ifinfo -The Texinfo language is described fully, starting with -@inforef{Top, , Texinfo, texinfo,Texinfo---The GNU Documentation Format}. +(The Texinfo language is described fully, starting with +@inforef{Top, , Texinfo, texinfo,Texinfo---The GNU Documentation Format}.) @end ifinfo For our purposes, it is enough to know three things about Texinfo input @@ -25379,8 +25671,7 @@ exits with a zero exit status, signifying OK: @cindex @code{extract.awk} program @example @c file eg/prog/extract.awk -# extract.awk --- extract files and run programs -# from texinfo files +# extract.awk --- extract files and run programs from texinfo files @c endfile @ignore @c file eg/prog/extract.awk @@ -25394,8 +25685,7 @@ exits with a zero exit status, signifying OK: BEGIN @{ IGNORECASE = 1 @} -/^@@c(omment)?[ \t]+system/ \ -@{ +/^@@c(omment)?[ \t]+system/ @{ if (NF < 3) @{ e = ("extract: " FILENAME ":" FNR) e = (e ": badly formed `system' line") @@ -25452,8 +25742,7 @@ line. That line is then printed to the output file: @example @c file eg/prog/extract.awk -/^@@c(omment)?[ \t]+file/ \ -@{ +/^@@c(omment)?[ \t]+file/ @{ if (NF != 3) @{ e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") print e > "/dev/stderr" @@ -25513,7 +25802,7 @@ The @code{END} rule handles the final cleanup, closing the open file: function unexpected_eof() @{ printf("extract: %s:%d: unexpected EOF or error\n", - FILENAME, FNR) > "/dev/stderr" + FILENAME, FNR) > "/dev/stderr" exit 1 @} @end group @@ -25541,7 +25830,7 @@ While @command{sed} is a complicated program in its own right, its most common use is to perform global substitutions in the middle of a pipeline: @example -command1 < orig.data | sed 's/old/new/g' | command2 > result +@var{command1} < orig.data | sed 's/old/new/g' | @var{command2} > result @end example Here, @samp{s/old/new/g} tells @command{sed} to look for the regexp @@ -25773,6 +26062,7 @@ should be the @command{awk} program. If there are no command-line arguments left, @command{igawk} prints an error message and exits. Otherwise, the first argument is appended to @code{program}. In any case, after the arguments have been processed, +the shell variable @code{program} contains the complete text of the original @command{awk} program. @@ -25895,8 +26185,8 @@ the path, and an attempt is made to open the generated @value{FN}. The only way to test if a file can be read in @command{awk} is to go ahead and try to read it with @code{getline}; this is what @code{pathto()} does.@footnote{On some very old versions of @command{awk}, the test -@samp{getline junk < t} can loop forever if the file exists but is empty. -Caveat emptor.} If the file can be read, it is closed and the @value{FN} +@samp{getline junk < t} can loop forever if the file exists but is empty.} +If the file can be read, it is closed and the @value{FN} is returned: @ignore @@ -26096,12 +26386,10 @@ in C or C++, and it is frequently easier to do certain kinds of string and argument manipulation using the shell than it is in @command{awk}. Finally, @command{igawk} shows that it is not always necessary to add new -features to a program; they can often be layered on top. -@ignore -With @command{igawk}, -there is no real reason to build @code{@@include} processing into -@command{gawk} itself. -@end ignore +features to a program; they can often be layered on top.@footnote{@command{gawk} +does @code{@@include} processing itself in order to support the use +of @command{awk} programs as Web CGI scripts.} + @c ENDOFRANGE libfex @c ENDOFRANGE flibex @c ENDOFRANGE awkpex @@ -26119,12 +26407,11 @@ One word is an anagram of another if both words contain the same letters (for example, ``babbling'' and ``blabbing''). -An elegant algorithm is presented in Column 2, Problem C of -Jon Bentley's @cite{Programming Pearls}, second edition. -The idea is to give words that are anagrams a common signature, -sort all the words together by their signature, and then print them. -Dr.@: Bentley observes that taking the letters in each word and -sorting them produces that common signature. +Column 2, Problem C of Jon Bentley's @cite{Programming Pearls}, second +edition, presents an elegant algorithm. The idea is to give words that +are anagrams a common signature, sort all the words together by their +signature, and then print them. Dr.@: Bentley observes that taking the +letters in each word and sorting them produces that common signature. The following program uses arrays of arrays to bring together words with the same signature and array sorting to print the words @@ -26358,7 +26645,7 @@ BEGIN { @itemize @value{BULLET} @item -The functions provided in this @value{CHAPTER} and the previous one +The programs provided in this @value{CHAPTER} continue on the theme that reading programs is an excellent way to learn Good Programming. @@ -26396,7 +26683,7 @@ mailing labels, and finding anagrams. @enumerate @item Rewrite @file{cut.awk} (@pxref{Cut Program}) -using @code{split()} with @code{""} as the seperator. +using @code{split()} with @code{""} as the separator. @item In @ref{Egrep Program}, we mentioned that @samp{egrep -i} could be @@ -26428,7 +26715,7 @@ conditions depending on its previous condition and on the present values of its inputs.''@footnote{This is the definition returned from entering @code{define: state machine} into Google.} Brian Kernighan suggests that -``an alternative approach to state mechines is to just read +``an alternative approach to state machines is to just read the input into an array, then use indexing. It's almost always easier code, and for most inputs where you would use this, just as fast.'' Rewrite the logic to follow this @@ -26635,13 +26922,11 @@ discusses the ability to dynamically add new built-in functions to @cindex constants, nondecimal If you run @command{gawk} with the @option{--non-decimal-data} option, -you can have nondecimal constants in your input data: +you can have nondecimal values in your input data: -@c line break here for small book format @example $ @kbd{echo 0123 123 0x123 |} -> @kbd{gawk --non-decimal-data '@{ printf "%d, %d, %d\n",} -> @kbd{$1, $2, $3 @}'} +> @kbd{gawk --non-decimal-data '@{ printf "%d, %d, %d\n", $1, $2, $3 @}'} @print{} 83, 123, 291 @end example @@ -26682,6 +26967,8 @@ Instead, use the @code{strtonum()} function to convert your data (@pxref{String Functions}). This makes your programs easier to write and easier to read, and leads to less surprising results. + +This option may disappear in a future version of @command{gawk}. @end quotation @node Array Sorting @@ -26716,7 +27003,9 @@ pre-defined values to @code{PROCINFO["sorted_in"]} in order to control the order in which @command{gawk} traverses an array during a @code{for} loop. -In addition, the value of @code{PROCINFO["sorted_in"]} can be a function name. +In addition, the value of @code{PROCINFO["sorted_in"]} can be a +function name.@footnote{This is why the predefined sorting orders +start with an @samp{@@} character, which cannot be part of an identifier.} This lets you traverse an array based on any custom criterion. The array elements are ordered according to the return value of this function. The comparison function should be defined with at least @@ -26848,7 +27137,7 @@ according to login name. The following program sorts records by a specific field position and can be used for this purpose: @example -# sort.awk --- simple program to sort by field position +# passwd-sort.awk --- simple program to sort by field position # field position is specified by the global variable POS function cmp_field(i1, v1, i2, v2) @@ -26907,7 +27196,7 @@ As mentioned above, the order of the indices is arbitrary if two elements compare equal. This is usually not a problem, but letting the tied elements come out in arbitrary order can be an issue, especially when comparing item values. The partial ordering of the equal elements -may change during the next loop traversal, if other elements are added or +may change the next time the array is traversed, if other elements are added or removed from the array. One way to resolve ties when comparing elements with otherwise equal values is to include the indices in the comparison rules. Note that doing this may make the loop traversal less efficient, @@ -27076,7 +27365,6 @@ come into play; comparisons are based on character values only.@footnote{This is true because locale-based comparison occurs only when in POSIX compatibility mode, and since @code{asort()} and @code{asorti()} are @command{gawk} extensions, they are not available in that case.} -Caveat Emptor. @node Two-way I/O @section Two-Way Communications with Another Process @@ -27142,7 +27430,7 @@ for example, @file{/tmp} will not do, as another user might happen to be using a temporary file with the same name.@footnote{Michael Brennan suggests the use of @command{rand()} to generate unique @value{FN}s. This is a valid point; nevertheless, temporary files -remain more difficult than two-way pipes.} @c 8/2014 +remain more difficult to use than two-way pipes.} @c 8/2014 @cindex coprocesses @cindex input/output, two-way @@ -27281,21 +27569,23 @@ using regular pipes. @cindex @code{EMISTERED} @ifnotdocbook @quotation -@code{EMISTERED}:@* +@code{EMRED}:@* @ @ @ @ @i{A host is a host from coast to coast,@* -@ @ @ @ and no-one can talk to host that's close,@* +@ @ @ @ and nobody talks to a host that's close,@* @ @ @ @ unless the host that isn't close@* -@ @ @ @ is busy hung or dead.} +@ @ @ @ is busy, hung, or dead.} +@author Mike O'Brien (aka Mr.@: Protocol) @end quotation @end ifnotdocbook @docbook <blockquote> +<attribution>Mike O'Brien (aka Mr. Protocol)</attribution> <literallayout class="normal"><literal>EMISTERED</literal>: <emphasis>A host is a host from coast to coast,</emphasis> <emphasis>and no-one can talk to host that's close,</emphasis> <emphasis>unless the host that isn't close</emphasis> - <emphasis>is busy hung or dead.</emphasis></literallayout> + <emphasis>is busy, hung, or dead.</emphasis></literallayout> </blockquote> @end docbook @@ -27326,7 +27616,7 @@ the system default, most likely IPv4. @item protocol The protocol to use over IP. This must be either @samp{tcp}, or @samp{udp}, for a TCP or UDP IP connection, -respectively. The use of TCP is recommended for most applications. +respectively. TCP should be used for most applications. @item local-port @cindex @code{getaddrinfo()} function (C library) @@ -27359,10 +27649,10 @@ Consider the following very simple example: @example BEGIN @{ - Service = "/inet/tcp/0/localhost/daytime" - Service |& getline - print $0 - close(Service) + Service = "/inet/tcp/0/localhost/daytime" + Service |& getline + print $0 + close(Service) @} @end example @@ -27465,9 +27755,9 @@ in the morning to work.) @cindex @code{BEGIN} pattern, and profiling @cindex @code{END} pattern, and profiling @example - # gawk profile, created Thu Feb 27 05:16:21 2014 + # gawk profile, created Mon Sep 29 05:16:21 2014 - # BEGIN block(s) + # BEGIN rule(s) BEGIN @{ 1 print "First BEGIN rule" @@ -27494,7 +27784,7 @@ in the morning to work.) @} @} - # END block(s) + # END rule(s) END @{ 1 print "First END rule" @@ -27604,8 +27894,7 @@ The profiled version of your program may not look exactly like what you typed when you wrote it. This is because @command{gawk} creates the profiled version by ``pretty printing'' its internal representation of the program. The advantage to this is that @command{gawk} can produce -a standard representation. The disadvantage is that all source-code -comments are lost. +a standard representation. Also, things such as: @example @@ -27622,7 +27911,7 @@ come out as: @end example @noindent -which is correct, but possibly surprising. +which is correct, but possibly unexpected. @cindex profiling @command{awk} programs, dynamically @cindex @command{gawk} program, dynamic profiling @@ -27654,7 +27943,7 @@ $ @kbd{kill -USR1 13992} @noindent As usual, the profiled version of the program is written to -@file{awkprof.out}, or to a different file if one specified with +@file{awkprof.out}, or to a different file if one was specified with the @option{--profile} option. Along with the regular profile, as shown earlier, the profile file @@ -27702,6 +27991,23 @@ When called this way, @command{gawk} ``pretty prints'' the program into Once upon a time, the @option{--pretty-print} option would also run your program. This is is no longer the case. @end quotation + +There is a significant difference between the output created when +profiling, and that created when pretty-printing. Pretty-printed output +preserves the original comments that were in the program, although their +placement may not correspond exactly to their original locations in the +source code. + +However, as a deliberate design decision, profiling output @emph{omits} +the original program's comments. This allows you to focus on the +execution count data and helps you avoid the temptation to use the +profiler for pretty-printing. + +Additionally, pretty-printed output does not have the leading indentation +that the profiling output does. This makes it easy to pretty-print your +code once development is completed, and then use the result as the final +version of your program. + @c ENDOFRANGE awkp @c ENDOFRANGE proawk @@ -27714,6 +28020,7 @@ The @option{--non-decimal-data} option causes @command{gawk} to treat octal- and hexadecimal-looking input data as octal and hexadecimal. This option should be used with caution or not at all; use of @code{strtonum()} is preferable. +Note that this option may disappear in a future version of @command{gawk}. @item You can take over complete control of sorting in @samp{for (@var{indx} in @var{array})} @@ -27727,15 +28034,15 @@ those functions sort arrays. Or you may provide one of the predefined control strings that work for @code{PROCINFO["sorted_in"]}. @item -You can use the @samp{|&} operator to create a two-way pipe to a co-process. -You read from the co-process with @code{getline} and write to it with @code{print} -or @code{printf}. Use @code{close()} to close off the co-process completely, or +You can use the @samp{|&} operator to create a two-way pipe to a coprocess. +You read from the coprocess with @code{getline} and write to it with @code{print} +or @code{printf}. Use @code{close()} to close off the coprocess completely, or optionally, close off one side of the two-way communications. @item -By using special ``@value{FN}s'' with the @samp{|&} operator, you can open a +By using special @value{FN}s with the @samp{|&} operator, you can open a TCP/IP (or UDP/IP) connection to remote hosts in the Internet. @command{gawk} -supports both IPv4 an IPv6. +supports both IPv4 and IPv6. @item You can generate statement count profiles of your program. This can help you @@ -27973,7 +28280,7 @@ In June 2001 Bruno Haible wrote: This information is accessed via the POSIX character classes in regular expressions, such as @code{/[[:alnum:]]/} -(@pxref{Regexp Operators}). +(@pxref{Bracket Expressions}). @cindex monetary information, localization @cindex currency symbols, localization @@ -28056,7 +28363,7 @@ default arguments. Return the plural form used for @var{number} of the translation of @var{string1} and @var{string2} in text domain @var{domain} for locale category @var{category}. @var{string1} is the -English singular variant of a message, and @var{string2} the English plural +English singular variant of a message, and @var{string2} is the English plural variant of the same message. The default value for @var{domain} is the current value of @code{TEXTDOMAIN}. The default value for @var{category} is @code{"LC_MESSAGES"}. @@ -28144,9 +28451,11 @@ This example would be better done with @code{dcngettext()}: @example if (groggy) - message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") + message = dcngettext("%d customer disturbing me\n", + "%d customers disturbing me\n", "adminprog") else - message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") + message = dcngettext("enjoying %d customer\n", + "enjoying %d customers\n", "adminprog") printf(message, ncustomers) @end example @@ -28218,7 +28527,7 @@ First, use the @option{--gen-pot} command-line option to create the initial @file{.pot} file: @example -$ @kbd{gawk --gen-pot -f guide.awk > guide.pot} +gawk --gen-pot -f guide.awk > guide.pot @end example @cindex @code{xgettext} utility @@ -28282,11 +28591,11 @@ example, @samp{string} is the first argument and @samp{length(string)} is the se @example $ @kbd{gawk 'BEGIN @{} -> @kbd{string = "Dont Panic"} +> @kbd{string = "Don\47t Panic"} > @kbd{printf "%2$d characters live in \"%1$s\"\n",} > @kbd{string, length(string)} > @kbd{@}'} -@print{} 10 characters live in "Dont Panic" +@print{} 11 characters live in "Don't Panic" @end example If present, positional specifiers come first in the format specification, @@ -28498,7 +28807,8 @@ msgstr "Like, the scoop is" @cindex GNU/Linux The next step is to make the directory to hold the binary message object file and then to create the @file{guide.mo} file. -We pretend that our file is to be used in the @code{en_US.UTF-8} locale. +We pretend that our file is to be used in the @code{en_US.UTF-8} locale, +since we have to use a locale name known to the C @command{gettext} routines. The directory layout shown here is standard for GNU @command{gettext} on GNU/Linux systems. Other versions of @command{gettext} may use a different layout: @@ -28519,8 +28829,8 @@ $ @kbd{mkdir en_US.UTF-8 en_US.UTF-8/LC_MESSAGES} The @command{msgfmt} utility does the conversion from human-readable @file{.po} file to machine-readable @file{.mo} file. By default, @command{msgfmt} creates a file named @file{messages}. -This file must be renamed and placed in the proper directory so that -@command{gawk} can find it: +This file must be renamed and placed in the proper directory (using +the @option{-o} option) so that @command{gawk} can find it: @example $ @kbd{msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo} @@ -28563,8 +28873,8 @@ complete detail in @cite{GNU gettext tools}}.) @end ifnotinfo As of this writing, the latest version of GNU @command{gettext} is -@uref{ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.1.tar.gz, -@value{PVERSION} 0.19.1}. +@uref{ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.3.tar.gz, +@value{PVERSION} 0.19.3}. If a translation of @command{gawk}'s messages exists, then @command{gawk} produces usage messages, warnings, @@ -28652,7 +28962,7 @@ the discussion of debugging in @command{gawk}. @subsection Debugging in General (If you have used debuggers in other languages, you may want to skip -ahead to the next section on the specific features of the @command{awk} +ahead to the next section on the specific features of the @command{gawk} debugger.) Of course, a debugging program cannot remove bugs for you, since it has @@ -28692,7 +29002,7 @@ is going wrong (or, for that matter, to better comprehend a perfectly functional program that you or someone else wrote). @node Debugging Terms -@subsection Additional Debugging Concepts +@subsection Debugging Concepts Before diving in to the details, we need to introduce several important concepts that apply to just about all debuggers. @@ -28781,8 +29091,8 @@ as our example. @cindex starting the debugger @cindex debugger, how to start -Starting the debugger is almost exactly like running @command{gawk}, -except you have to pass an additional option @option{--debug} or the +Starting the debugger is almost exactly like running @command{gawk} normally, +except you have to pass an additional option @option{--debug}, or the corresponding short option @option{-D}. The file(s) containing the program and any supporting code are given on the command line as arguments to one or more @option{-f} options. (@command{gawk} is not designed @@ -28800,6 +29110,7 @@ this syntax is slightly different from what they are used to. With the @command{gawk} debugger, you give the arguments for running the program in the command line to the debugger rather than as part of the @code{run} command at the debugger prompt.) +The @option{-1} is an option to @file{uniq.awk}. Instead of immediately running the program on @file{inputfile}, as @command{gawk} would ordinarily do, the debugger merely loads all @@ -28981,7 +29292,7 @@ gawk> @kbd{p n m alast aline} This is kind of disappointing, though. All we found out is that there are five elements in @code{alast}; @code{m} and @code{aline} don't have -values yet since we are at line 68 but haven't executed it yet. +values since we are at line 68 but haven't executed it yet. This information is useful enough (we now know that none of the words were accidentally left out), but what if we want to see inside the array? @@ -29174,7 +29485,8 @@ Delete breakpoint(s) set at entry to function @var{function}. @cindex breakpoint condition @item @code{condition} @var{n} @code{"@var{expression}"} Add a condition to existing breakpoint or watchpoint @var{n}. The -condition is an @command{awk} expression that the debugger evaluates +condition is an @command{awk} expression @emph{enclosed in double quotes} +that the debugger evaluates whenever the breakpoint or watchpoint is reached. If the condition is true, then the debugger stops execution and prompts for a command. Otherwise, the debugger continues executing the program. If the condition expression is @@ -29362,7 +29674,7 @@ see the output shown under @code{dump} in @ref{Miscellaneous Debugger Commands}. @item @code{until} [[@var{filename}@code{:}]@var{n} | @var{function}] @itemx @code{u} [[@var{filename}@code{:}]@var{n} | @var{function}] Without any argument, continue execution until a line past the current -line in current stack frame is reached. With an argument, +line in the current stack frame is reached. With an argument, continue execution until the specified location is reached, or the current stack frame returns. @end table @@ -29426,7 +29738,7 @@ gawk> @kbd{print $3} @noindent This prints the third field in the input record (if the specified field does not exist, it prints @samp{Null field}). A variable can be an array element, with -the subscripts being constant values. To print the contents of an array, +the subscripts being constant string values. To print the contents of an array, prefix the name of the array with the @samp{@@} symbol: @example @@ -29492,7 +29804,7 @@ watch list. @end table @node Execution Stack -@subsection Dealing with the Stack +@subsection Working with the Stack Whenever you run a program which contains any function calls, @command{gawk} maintains a stack of all of the function calls leading up @@ -29503,16 +29815,22 @@ functions which called the one you are in. The commands for doing this are: @table @asis @cindex debugger commands, @code{bt} (@code{backtrace}) @cindex debugger commands, @code{backtrace} +@cindex debugger commands, @code{where} (@code{backtrace}) @cindex @code{backtrace} debugger command @cindex @code{bt} debugger command (alias for @code{backtrace}) +@cindex @code{where} debugger command +@cindex @code{where} debugger command (alias for @code{backtrace}) @cindex call stack, display in debugger @cindex traceback, display in debugger @item @code{backtrace} [@var{count}] @itemx @code{bt} [@var{count}] +@itemx @code{where} [@var{count}] Print a backtrace of all function calls (stack frames), or innermost @var{count} frames if @var{count} > 0. Print the outermost @var{count} frames if @var{count} < 0. The backtrace displays the name and arguments to each function, the source @value{FN}, and the line number. +The alias @code{where} for @code{backtrace} is provided for long-time +GDB users who may be used to that command. @cindex debugger commands, @code{down} @cindex @code{down} debugger command @@ -29562,7 +29880,7 @@ The value for @var{what} should be one of the following: @table @code @item args @cindex show function arguments, in debugger -Arguments of the selected frame. +List arguments of the selected frame. @item break @cindex show breakpoints @@ -29574,7 +29892,7 @@ List all items in the automatic display list. @item frame @cindex describe call stack frame, in debugger -Description of the selected stack frame. +Give a description of the selected stack frame. @item functions @cindex list function definitions, in debugger @@ -29583,11 +29901,11 @@ line numbers. @item locals @cindex show local variables, in debugger -Local variables of the selected frame. +List local variables of the selected frame. @item source @cindex show name of current source file, in debugger -The name of the current source file. Each time the program stops, the +Print the name of the current source file. Each time the program stops, the current source file is the file containing the current instruction. When the debugger first starts, the current source file is the first file included via the @option{-f} option. The @@ -29704,6 +30022,7 @@ commands in a program. This can be very enlightening, as the following partial dump of Davide Brini's obfuscated code (@pxref{Signature Program}) demonstrates: +@c FIXME: This will need updating if num-handler branch is ever merged in. @smallexample gawk> @kbd{dump} @print{} # BEGIN @@ -29777,7 +30096,7 @@ are as follows: @c nested table @table @asis -@item @code{-} +@item @code{-} (Minus) Print lines before the lines last printed. @item @code{+} @@ -29865,7 +30184,7 @@ and @end table @node Limitations -@section Limitations and Future Plans +@section Limitations We hope you find the @command{gawk} debugger useful and enjoyable to work with, but as with any program, especially in its early releases, it still has @@ -29913,8 +30232,10 @@ executing, short programs. The @command{gawk} debugger only accepts source supplied with the @option{-f} option. @end itemize +@ignore Look forward to a future release when these and other missing features may be added, and of course feel free to try to add them yourself! +@end ignore @node Debugging Summary @section Summary @@ -29957,9 +30278,8 @@ and editing. @cindex floating-point, numbers@comma{} arbitrary precision This @value{CHAPTER} introduces some basic concepts relating to -how computers do arithmetic and briefly lists the features in -@command{gawk} for performing arbitrary precision floating point -computations. It then proceeds to describe floating-point arithmetic, +how computers do arithmetic and defines some important terms. +It then proceeds to describe floating-point arithmetic, which is what @command{awk} uses for all its computations, including a discussion of arbitrary precision floating point arithmetic, which is a feature available only in @command{gawk}. It continues on to present @@ -30054,10 +30374,12 @@ Computers work with integer and floating point values of different ranges. Integer values are usually either 32 or 64 bits in size. Single precision floating point values occupy 32 bits, whereas double precision floating point values occupy 64 bits. Floating point values are always -signed. The possible ranges of values are shown in the following table. +signed. The possible ranges of values are shown in @ref{table-numeric-ranges}. +@float Table,table-numeric-ranges +@caption{Value Ranges for Different Numeric Representations} @multitable @columnfractions .34 .33 .33 -@headitem Numeric representation @tab Miniumum value @tab Maximum value +@headitem Numeric representation @tab Minimum value @tab Maximum value @item 32-bit signed integer @tab @minus{}2,147,483,648 @tab 2,147,483,647 @item 32-bit unsigned integer @tab 0 @tab 4,294,967,295 @item 64-bit signed integer @tab @minus{}9,223,372,036,854,775,808 @tab 9,223,372,036,854,775,807 @@ -30065,6 +30387,7 @@ signed. The possible ranges of values are shown in the following table. @item Single precision floating point (approximate) @tab @code{1.175494e-38} @tab @code{3.402823e+38} @item Double precision floating point (approximate) @tab @code{2.225074e-308} @tab @code{1.797693e+308} @end multitable +@end float @node Math Definitions @section Other Stuff To Know @@ -30092,14 +30415,12 @@ A special value representing infinity. Operations involving another number and infinity produce infinity. @item NaN -``Not A Number.''@footnote{Thanks -to Michael Brennan for this description, which I have paraphrased, and -for the examples}. -A special value that results from attempting a -calculation that has no answer as a real number. In such a case, -programs can either receive a floating-point exception, or get @code{NaN} -back as the result. The IEEE 754 standard recommends that systems return -@code{NaN}. Some examples: +``Not A Number.''@footnote{Thanks to Michael Brennan for this description, +which we have paraphrased, and for the examples.} A special value that +results from attempting a calculation that has no answer as a real number. +In such a case, programs can either receive a floating-point exception, +or get @code{NaN} back as the result. The IEEE 754 standard recommends +that systems return @code{NaN}. Some examples: @table @code @item sqrt(-1) @@ -30173,9 +30494,9 @@ to allow greater precisions and larger exponent ranges. field values for the basic IEEE 754 binary formats: @float Table,table-ieee-formats -@caption{Basic IEEE Format Context Values} +@caption{Basic IEEE Format Values} @multitable @columnfractions .20 .20 .20 .20 .20 -@headitem Name @tab Total bits @tab Precision @tab emin @tab emax +@headitem Name @tab Total bits @tab Precision @tab Minimum exponent @tab Maximum exponent @item Single @tab 32 @tab 24 @tab @minus{}126 @tab +127 @item Double @tab 64 @tab 53 @tab @minus{}1022 @tab +1023 @item Quadruple @tab 128 @tab 113 @tab @minus{}16382 @tab +16383 @@ -30188,18 +30509,18 @@ one extra bit of significand. @end quotation @node MPFR features -@section Arbitrary Precison Arithmetic Features In @command{gawk} +@section Arbitrary Precision Arithmetic Features In @command{gawk} -By default, @command{gawk} uses the double precision floating point values +By default, @command{gawk} uses the double precision floating-point values supplied by the hardware of the system it runs on. However, if it was -compiled to do, @command{gawk} uses the @uref{http://www.mpfr.org, GNU -MPFR} and @uref{http://gmplib.org, GNU MP} (GMP) libraries for arbitrary +compiled to do so, @command{gawk} uses the @uref{http://www.mpfr.org +GNU MPFR} and @uref{http://gmplib.org, GNU MP} (GMP) libraries for arbitrary precision arithmetic on numbers. You can see if MPFR support is available like so: @example $ @kbd{gawk --version} -@print{} GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) +@print{} GNU Awk 4.1.2, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) @print{} Copyright (C) 1989, 1991-2014 Free Software Foundation. @dots{} @end example @@ -30219,11 +30540,12 @@ results. With the @option{-M} command-line option, all floating-point arithmetic operators and numeric functions can yield results to any desired precision level supported by MPFR. -Two built-in variables, @code{PREC} and @code{ROUNDMODE}, +Two predefined variables, @code{PREC} and @code{ROUNDMODE}, provide control over the working precision and the rounding mode. The precision and the rounding mode are set globally for every operation to follow. -@xref{Auto-set}, for more information. +@xref{Setting precision}, and @ref{Setting the rounding mode}, +for more information. @node FP Math Caution @section Floating Point Arithmetic: Caveat Emptor! @@ -30337,6 +30659,10 @@ else # not ok @end example +@noindent +(We assume that you have a simple absolute value function named +@code{abs()} defined elsewhere in your program.) + @node Errors accumulate @subsubsection Errors Accumulate @@ -30423,7 +30749,7 @@ It is easy to forget that the finite number of bits used to store the value is often just an approximation after proper rounding. The test for equality succeeds if and only if @emph{all} bits in the two operands are exactly the same. Since this is not necessarily true after floating-point -computations with a particular precision and effective rounding rule, +computations with a particular precision and effective rounding mode, a straight test for equality may not work. Instead, compare the two numbers to see if they are within the desirable delta of each other. @@ -30490,7 +30816,7 @@ $ @kbd{gawk -f pi2.awk} the precision or accuracy of individual numbers. Performing an arithmetic operation or calling a built-in function rounds the result to the current working precision. The default working precision is 53 bits, which you can -modify using the built-in variable @code{PREC}. You can also set the +modify using the predefined variable @code{PREC}. You can also set the value to one of the predefined case-insensitive strings shown in @ref{table-predefined-precision-strings}, to emulate an IEEE 754 binary format. @@ -30522,7 +30848,7 @@ Be wary of floating-point constants! When reading a floating-point constant from program source code, @command{gawk} uses the default precision (that of a C @code{double}), unless overridden by an assignment to the special variable @code{PREC} on the command line, to store it -internally as a MPFR number. Changing the precision using @code{PREC} +internally as an MPFR number. Changing the precision using @code{PREC} in the program text does @emph{not} change the precision of a constant. If you need to represent a floating-point constant at a higher precision @@ -30660,15 +30986,15 @@ the following computes 5<superscript>4<superscript>3<superscript>2</superscript></superscript></superscript>, @c @end docbook the result of which is beyond the -limits of ordinary hardware double-precision floating point values: +limits of ordinary hardware double precision floating point values: @example $ @kbd{gawk -M 'BEGIN @{} > @kbd{x = 5^4^3^2} -> @kbd{print "# of digits =", length(x)} +> @kbd{print "number of digits =", length(x)} > @kbd{print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)} > @kbd{@}'} -@print{} # of digits = 183231 +@print{} number of digits = 183231 @print{} 62060698786608744707 ... 92256259918212890625 @end example @@ -30770,7 +31096,7 @@ using this user-defined function: @end ignore @c file eg/lib/div.awk -function div(numerator, denominator, result, i) +function div(numerator, denominator, result) @{ split("", result) @@ -30784,6 +31110,80 @@ function div(numerator, denominator, result, i) @c endfile @end example +The following example program, contributed by Katie Wasserman, +uses @code{div()} to +compute the digits of @value{PI} to as many places as you +choose to set: + +@example +@c file eg/prog/pi.awk +# pi.awk --- compute the digits of pi +@c endfile +@c endfile +@ignore +@c file eg/prog/pi.awk +# +# Katie Wasserman, katie@@wass.net +# August 2014 +@c endfile +@end ignore +@c file eg/prog/pi.awk + +BEGIN @{ + digits = 100000 + two = 2 * 10 ^ digits + pi = two + for (m = digits * 4; m > 0; --m) @{ + d = m * 2 + 1 + x = pi * m + div(x, d, result) + pi = result["quotient"] + pi = pi + two + @} + print pi +@} +@c endfile +@end example + +@ignore +Date: Wed, 20 Aug 2014 10:19:11 -0400 +To: arnold@skeeve.com +From: Katherine Wasserman <katie@wass.net> +Subject: Re: computation of digits of pi? + +Arnold, + +>The program that you sent to compute the digits of pi using div(). Is +>that some standard algorithm that every math student knows? If so, +>what's it called? + +It's not that well known but it's not that obscure either + +It's Euler's modification to Newton's method for calculating pi. + +Take a look at lines (23) - (25) here: http://mathworld.wolfram.com/PiFormulas.htm + +The algorithm I wrote simply expands the multiply by 2 and works from the innermost expression outwards. I used this to program HP calculators because it's quite easy to modify for tiny memory devices with smallish word sizes. + +http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899 + +-Katie +@end ignore + +When asked about the algorithm used, Katie replied: + +@quotation +It's not that well known but it's not that obscure either. +It's Euler's modification to Newton's method for calculating pi. +Take a look at lines (23) - (25) here: @uref{http://mathworld.wolfram.com/PiFormulas.htm}. + +The algorithm I wrote simply expands the multiply by 2 and works from +the innermost expression outwards. I used this to program HP calculators +because it's quite easy to modify for tiny memory devices with smallish +word sizes. See +@uref{http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899}. +@end quotation + @node POSIX Floating Point Problems @section Standards Versus Existing Practice @@ -30891,7 +31291,7 @@ Thus @samp{+nan} and @samp{+NaN} are the same. @itemize @value{BULLET} @item Most computer arithmetic is done using either integers or floating-point -values. The default for @command{awk} is to use double-precision +values. Standard @command{awk} uses double precision floating-point values. @item @@ -31010,7 +31410,7 @@ Extensions are written in C or C++, using the @dfn{Application Programming Interface} (API) defined for this purpose by the @command{gawk} developers. The rest of this @value{CHAPTER} explains the facilities that the API provides and how to use -them, and presents a small sample extension. In addition, it documents +them, and presents a small example extension. In addition, it documents the sample extensions included in the @command{gawk} distribution, and describes the @code{gawkextlib} project. @ifclear FOR_PRINT @@ -31026,10 +31426,14 @@ goals and design. @node Plugin License @section Extension Licensing -Every dynamic extension should define the global symbol -@code{plugin_is_GPL_compatible} to assert that it has been licensed under -a GPL-compatible license. If this symbol does not exist, @command{gawk} -emits a fatal error and exits when it tries to load your extension. +Every dynamic extension must be distributed under a license that is +compatible with the GNU GPL (@pxref{Copying}). + +In order for the extension to tell @command{gawk} that it is +properly licensed, the extension must define the global symbol +@code{plugin_is_GPL_compatible}. If this symbol does not exist, +@command{gawk} emits a fatal error and exits when it tries to load +your extension. The declared type of the symbol should be @code{int}. It does not need to be in any allocated section, though. The code merely asserts that @@ -31044,7 +31448,7 @@ int plugin_is_GPL_compatible; Communication between @command{gawk} and an extension is two-way. First, when an extension -is loaded, it is passed a pointer to a @code{struct} whose fields are +is loaded, @command{gawk} passes it a pointer to a @code{struct} whose fields are function pointers. @ifnotdocbook This is shown in @ref{figure-load-extension}. @@ -31080,29 +31484,29 @@ This is shown in @inlineraw{docbook, <xref linkend="figure-load-extension"/>}. The extension can call functions inside @command{gawk} through these function pointers, at runtime, without needing (link-time) access to @command{gawk}'s symbols. One of these function pointers is to a -function for ``registering'' new built-in functions. +function for ``registering'' new functions. @ifnotdocbook -This is shown in @ref{figure-load-new-function}. +This is shown in @ref{figure-register-new-function}. @end ifnotdocbook @ifdocbook -This is shown in @inlineraw{docbook, <xref linkend="figure-load-new-function"/>}. +This is shown in @inlineraw{docbook, <xref linkend="figure-register-new-function"/>}. @end ifdocbook @ifnotdocbook -@float Figure,figure-load-new-function -@caption{Loading The New Function} +@float Figure,figure-register-new-function +@caption{Registering A New Function} @ifinfo -@center @image{api-figure2, , , Loading The New Function, txt} +@center @image{api-figure2, , , Registering A New Function, txt} @end ifinfo @ifnotinfo -@center @image{api-figure2, , , Loading The New Function} +@center @image{api-figure2, , , Registering A New Function} @end ifnotinfo @end float @end ifnotdocbook @docbook -<figure id="figure-load-new-function" float="0"> -<title>Loading The New Function</title> +<figure id="figure-register-new-function" float="0"> +<title>Registering A New Function</title> <mediaobject> <imageobject role="web"><imagedata fileref="api-figure2.png" format="PNG"/></imageobject> </mediaobject> @@ -31152,8 +31556,8 @@ and understandable. Although all of this sounds somewhat complicated, the result is that extension code is quite straightforward to write and to read. You can -see this in the sample extensions @file{filefuncs.c} (@pxref{Extension -Example}) and also the @file{testext.c} code for testing the APIs. +see this in the sample extension @file{filefuncs.c} (@pxref{Extension +Example}) and also in the @file{testext.c} code for testing the APIs. Some other bits and pieces: @@ -31187,13 +31591,13 @@ This (rather large) @value{SECTION} describes the API in detail. @menu * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with @command{gawk}. * Printing Messages:: Functions for printing messages. * Updating @code{ERRNO}:: Functions for updating @code{ERRNO}. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -31212,6 +31616,9 @@ API function pointers are provided for the following kinds of operations: @itemize @value{BULLET} @item +Allocating, reallocating, and releasing memory. + +@item Registration functions. You may register: @itemize @value{MINUS} @item @@ -31244,9 +31651,6 @@ Symbol table access: retrieving a global variable, creating one, or changing one. @item -Allocating, reallocating, and releasing memory. - -@item Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -31314,15 +31718,15 @@ does not support this keyword, you should either place All pointers filled in by @command{gawk} point to memory managed by @command{gawk} and should be treated by the extension as read-only. Memory for @emph{all} strings passed into @command{gawk} -from the extension @emph{must} come from calling the API-provided function -pointers @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}, +from the extension @emph{must} come from calling one of +@code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}, and is managed by @command{gawk} from then on. @item The API defines several simple @code{struct}s that map values as seen from @command{awk}. A value can be a @code{double}, a string, or an array (as in multidimensional arrays, or when creating a new array). -String values maintain both pointer and length since embedded @value{NUL} +String values maintain both pointer and length since embedded @sc{nul} characters are allowed. @quotation NOTE @@ -31335,7 +31739,7 @@ and also how characters are likely to be input and output from files. @item When retrieving a value (such as a parameter or that of a global variable or array element), the extension requests a specific type (number, string, -scalars, value cookie, array, or ``undefined''). When the request is +scalar, value cookie, array, or ``undefined''). When the request is ``undefined,'' the returned value will have the real underlying type. However, if the request and actual type don't match, the access function @@ -31398,8 +31802,8 @@ A simple boolean type. This represents a mutable string. @command{gawk} owns the memory pointed to if it supplied the value. Otherwise, it takes ownership of the memory pointed to. -@strong{Such memory must come from calling the API-provided function -pointers @code{api_malloc()}, @code{api_calloc()}, or @code{api_realloc()}!} +@strong{Such memory must come from calling one of the +@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()} functions!} As mentioned earlier, strings are maintained using the current multibyte encoding. @@ -31454,7 +31858,7 @@ Scalar values in @command{awk} are either numbers or strings. The indicates what is in the @code{union}. Representing numbers is easy---the API uses a C @code{double}. Strings -require more work. Since @command{gawk} allows embedded @value{NUL} bytes +require more work. Since @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. @@ -31494,7 +31898,7 @@ the cookie for getting the variable's value or for changing the variable's value. This is the @code{awk_scalar_t} type and @code{scalar_cookie} macro. Given a scalar cookie, @command{gawk} can directly retrieve or -modify the value, as required, without having to first find it. +modify the value, as required, without having to find it first. The @code{awk_value_cookie_t} type and @code{value_cookie} macro are similar. If you know that you wish to @@ -31504,149 +31908,6 @@ and then pass in that value cookie whenever you wish to set the value of a variable. This saves both storage space within the running @command{gawk} process as well as the time needed to create the value. -@node Requesting Values -@subsection Requesting Values - -All of the functions that return values from @command{gawk} -work in the same way. You pass in an @code{awk_valtype_t} value -to indicate what kind of value you expect. If the actual value -matches what you requested, the function returns true and fills -in the @code{awk_value_t} result. -Otherwise, the function returns false, and the @code{val_type} -member indicates the type of the actual value. You may then -print an error message, or reissue the request for the actual -value type, as appropriate. This behavior is summarized in -@ref{table-value-types-returned}. - -@c FIXME: Try to do this with spans... - -@float Table,table-value-types-returned -@caption{API Value Types Returned} -@docbook -<informaltable> -<tgroup cols="2"> - <colspec colwidth="50*"/><colspec colwidth="50*"/> - <thead> - <row><entry></entry><entry><para>Type of Actual Value:</para></entry></row> - </thead> - <tbody> - <row><entry></entry><entry></entry></row> - </tbody> -</tgroup> -<tgroup cols="6"> - <colspec colwidth="16.6*"/> - <colspec colwidth="16.6*"/> - <colspec colwidth="19.8*"/> - <colspec colwidth="15*"/> - <colspec colwidth="15*"/> - <colspec colwidth="16.6*"/> - <thead> - <row> - <entry></entry> - <entry></entry> - <entry><para>String</para></entry> - <entry><para>Number</para></entry> - <entry><para>Array</para></entry> - <entry><para>Undefined</para></entry> - </row> - </thead> - <tbody> - <row> - <entry></entry> - <entry><para><emphasis role="bold">String</emphasis></para></entry> - <entry><para>String</para></entry> - <entry><para>String</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Number</emphasis></para></entry> - <entry><para>Number if can be converted, else false</para></entry> - <entry><para>Number</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry><para><emphasis role="bold">Type</emphasis></para></entry> - <entry><para><emphasis role="bold">Array</emphasis></para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - <entry><para>Array</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry><para><emphasis role="bold">Requested:</emphasis></para></entry> - <entry><para><emphasis role="bold">Scalar</emphasis></para></entry> - <entry><para>Scalar</para></entry> - <entry><para>Scalar</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Undefined</emphasis></para></entry> - <entry><para>String</para></entry> - <entry><para>Number</para></entry> - <entry><para>Array</para></entry> - <entry><para>Undefined</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Value Cookie</emphasis></para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para> - </entry><entry><para>false</para></entry> - </row> - </tbody> -</tgroup> -</informaltable> -@end docbook - -@ifnotplaintext -@ifnotdocbook -@multitable @columnfractions .50 .50 -@headitem @tab Type of Actual Value: -@end multitable -@multitable @columnfractions .166 .166 .198 .15 .15 .166 -@headitem @tab @tab String @tab Number @tab Array @tab Undefined -@item @tab @b{String} @tab String @tab String @tab false @tab false -@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab false @tab false -@item @b{Type} @tab @b{Array} @tab false @tab false @tab Array @tab false -@item @b{Requested:} @tab @b{Scalar} @tab Scalar @tab Scalar @tab false @tab false -@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined -@item @tab @b{Value Cookie} @tab false @tab false @tab false @tab false -@end multitable -@end ifnotdocbook -@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 | | | | | -+-----------+-----------+------------+------------+-----------+-----------+ -@end example -@end ifplaintext -@end float - @node Memory Allocation Functions @subsection Memory Allocation Functions and Convenience Macros @cindex allocating memory for extensions @@ -31655,22 +31916,24 @@ value type, as appropriate. This behavior is summarized in The API provides a number of @dfn{memory allocation} functions for allocating memory that can be passed to @command{gawk}, as well as a number of convenience macros. +This @value{SUBSECTION} presents them all as function prototypes, in +the way that extension code would use them. @table @code @item void *gawk_malloc(size_t size); -Call @command{gawk}-provided @code{api_malloc()} to allocate storage that may +Call the correct version of @code{malloc()} to allocate storage that may be passed to @command{gawk}. @item void *gawk_calloc(size_t nmemb, size_t size); -Call @command{gawk}-provided @code{api_calloc()} to allocate storage that may +Call the correct version of @code{calloc()} to allocate storage that may be passed to @command{gawk}. @item void *gawk_realloc(void *ptr, size_t size); -Call @command{gawk}-provided @code{api_realloc()} to allocate storage that may +Call the correct version of @code{realloc()} to allocate storage that may be passed to @command{gawk}. @item void gawk_free(void *ptr); -Call @command{gawk}-provided @code{api_free()} to release storage that was +Call the correct version of @code{free()} to release storage that was allocated with @code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}. @end table @@ -31684,8 +31947,8 @@ unrelated version of @code{malloc()}, unexpected behavior would likely result. Two convenience macros may be used for allocating storage -from the API-provided function pointers @code{api_malloc()} and -@code{api_realloc()}. If the allocation fails, they cause @command{gawk} +from @code{gawk_malloc()} and +@code{gawk_realloc()}. If the allocation fails, they cause @command{gawk} to exit with a fatal error message. They should be used as if they were procedure calls that do not return a value. @@ -31699,7 +31962,7 @@ The arguments to this macro are as follows: The pointer variable to point at the allocated storage. @item type -The type of the pointer variable, used to create a cast for the call to @code{api_malloc()}. +The type of the pointer variable, used to create a cast for the call to @code{gawk_malloc()}. @item size The total number of bytes to be allocated. @@ -31723,8 +31986,8 @@ make_malloced_string(message, strlen(message), & result); @end example @item #define erealloc(pointer, type, size, message) @dots{} -This is like @code{emalloc()}, but it calls @code{api_realloc()}, -instead of @code{api_malloc()}. +This is like @code{emalloc()}, but it calls @code{gawk_realloc()}, +instead of @code{gawk_malloc()}. The arguments are the same as for the @code{emalloc()} macro. @end table @@ -31748,7 +32011,7 @@ for storage in @code{result}. It returns @code{result}. @itemx make_malloced_string(const char *string, size_t length, awk_value_t *result) This function creates a string value in the @code{awk_value_t} variable pointed to by @code{result}. It expects @code{string} to be a @samp{char *} -value pointing to data previously obtained from the api-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. The idea here +value pointing to data previously obtained from @code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}. The idea here is that the data is passed directly to @command{gawk}, which assumes responsibility for it. It returns @code{result}. @@ -31803,17 +32066,18 @@ The name of the new function. This is a regular C string. Function names must obey the rules for @command{awk} -identifiers. That is, they must begin with either a letter +identifiers. That is, they must begin with either an English letter 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); -This is a pointer to the C function that provides the desired +This is a pointer to the C function that provides the extension's functionality. -The function must fill in the result with either a number +The function must fill in @code{*result} with either a number or a string. @command{gawk} takes ownership of any string memory. -As mentioned earlier, string memory @strong{must} come from the api-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. +As mentioned earlier, string memory @strong{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. @@ -31824,7 +32088,7 @@ This is for the convenience of the calling code inside @command{gawk}. @item size_t num_expected_args; This is the 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. Following @command{awk} functions, it +arguments isn't what it expected. As with real @command{awk} functions, it is likely OK to ignore extra arguments. @end table @@ -32078,7 +32342,7 @@ If the concept of a ``record terminator'' makes sense, then @code{RT}, and @code{*rt_len} should be set to the length of the data. Otherwise, @code{*rt_len} should be set to zero. @code{gawk} makes its own copy of this data, so the -extension must manage the storage. +extension must manage this storage. @end table The return value is the length of the buffer pointed to by @@ -32357,10 +32621,148 @@ into a (possibly translated) string using the C @code{strerror()} function. Set @code{ERRNO} directly to the string value of @code{ERRNO}. @command{gawk} makes a copy of the value of @code{string}. -@item void unset_ERRNO(); +@item void unset_ERRNO(void); Unset @code{ERRNO}. @end table +@node Requesting Values +@subsection Requesting Values + +All of the functions that return values from @command{gawk} +work in the same way. You pass in an @code{awk_valtype_t} value +to indicate what kind of value you expect. If the actual value +matches what you requested, the function returns true and fills +in the @code{awk_value_t} result. +Otherwise, the function returns false, and the @code{val_type} +member indicates the type of the actual value. You may then +print an error message, or reissue the request for the actual +value type, as appropriate. This behavior is summarized in +@ref{table-value-types-returned}. + +@float Table,table-value-types-returned +@caption{API Value Types Returned} +@docbook +<informaltable> +<tgroup cols="6"> + <colspec colwidth="16.6*"/> + <colspec colwidth="16.6*"/> + <colspec colwidth="19.8*" colname="c3"/> + <colspec colwidth="15*" colname="c4"/> + <colspec colwidth="15*" colname="c5"/> + <colspec colwidth="16.6*" colname="c6"/> + <spanspec spanname="hspan" namest="c3" nameend="c6" align="center"/> + <thead> + <row><entry></entry><entry spanname="hspan"><para>Type of Actual Value:</para></entry></row> + <row> + <entry></entry> + <entry></entry> + <entry><para>String</para></entry> + <entry><para>Number</para></entry> + <entry><para>Array</para></entry> + <entry><para>Undefined</para></entry> + </row> + </thead> + <tbody> + <row> + <entry></entry> + <entry><para><emphasis role="bold">String</emphasis></para></entry> + <entry><para>String</para></entry> + <entry><para>String</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Number</emphasis></para></entry> + <entry><para>Number if can be converted, else false</para></entry> + <entry><para>Number</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry><para><emphasis role="bold">Type</emphasis></para></entry> + <entry><para><emphasis role="bold">Array</emphasis></para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + <entry><para>Array</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry><para><emphasis role="bold">Requested:</emphasis></para></entry> + <entry><para><emphasis role="bold">Scalar</emphasis></para></entry> + <entry><para>Scalar</para></entry> + <entry><para>Scalar</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Undefined</emphasis></para></entry> + <entry><para>String</para></entry> + <entry><para>Number</para></entry> + <entry><para>Array</para></entry> + <entry><para>Undefined</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Value Cookie</emphasis></para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para> + </entry><entry><para>false</para></entry> + </row> + </tbody> +</tgroup> +</informaltable> +@end docbook + +@ifnotplaintext +@ifnotdocbook +@multitable @columnfractions .50 .50 +@headitem @tab Type of Actual Value: +@end multitable +@c 10/2014: Thanks to Karl Berry for this bit to reduce the space: +@tex +\vglue-1.1\baselineskip +@end tex +@multitable @columnfractions .166 .166 .198 .15 .15 .166 +@headitem @tab @tab String @tab Number @tab Array @tab Undefined +@item @tab @b{String} @tab String @tab String @tab false @tab false +@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab false @tab false +@item @b{Type} @tab @b{Array} @tab false @tab false @tab Array @tab false +@item @b{Requested:} @tab @b{Scalar} @tab Scalar @tab Scalar @tab false @tab false +@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined +@item @tab @b{Value Cookie} @tab false @tab false @tab false @tab false +@end multitable +@end ifnotdocbook +@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 | | | | | ++-----------+-----------+------------+------------+-----------+-----------+ +@end example +@end ifplaintext +@end float + @node Accessing Parameters @subsection Accessing and Updating Parameters @@ -32415,7 +32817,7 @@ about symbols is termed a @dfn{symbol table}. Fill in the @code{awk_value_t} structure pointed to by @code{result} with the value of the variable named by the string @code{name}, which is a regular C string. @code{wanted} indicates the type of value expected. -Return true if the actual type matches @code{wanted}, false otherwise +Return true if the actual type matches @code{wanted}, false otherwise. In the latter case, @code{result->val_type} indicates the actual type (@pxref{table-value-types-returned}). @@ -32434,7 +32836,7 @@ 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 NOTE +@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 @@ -32456,14 +32858,14 @@ The following functions let you work with scalar cookies. @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted, @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result); Retrieve the current value of a scalar cookie. -Once you have obtained a scalar_cookie using @code{sym_lookup()}, you can +Once you have obtained a scalar cookie using @code{sym_lookup()}, you can use this function to get its value more efficiently. 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}. -Here too, the built-in variables may not be updated. +Here too, the predefined variables may not be updated. @end table It is not obvious at first glance how to work with scalar cookies or @@ -32518,7 +32920,7 @@ my_extension_init() /* install initial value */ sym_update("MAGIC_VAR", make_number(42.0, & value)); - /* get cookie */ + /* get the cookie */ sym_lookup("MAGIC_VAR", AWK_SCALAR, & value); /* save the cookie */ @@ -32567,7 +32969,8 @@ assign those values to variables using @code{sym_update()} or @code{sym_update_scalar()}, as you like. However, you can understand the point of cached values if you remember that -@emph{every} string value's storage @emph{must} come from @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. +@emph{every} string value's storage @emph{must} come from @code{gawk_malloc()}, +@code{gawk_calloc()} or @code{gawk_realloc()}. If you have 20 variables, all of which have the same string value, you must create 20 identical copies of the string.@footnote{Numeric values are clearly less problematic, requiring only a C @code{double} to store.} @@ -32638,7 +33041,7 @@ Using value cookies in this way saves considerable storage, since all of You might be wondering, ``Is this sharing problematic? What happens if @command{awk} code assigns a new value to @code{VAR1}, -are all the others be changed too?'' +are all the others changed too?'' That's a great question. The answer is that no, it's not a problem. Internally, @command{gawk} uses @dfn{reference-counted strings}. This means @@ -32693,7 +33096,7 @@ with the @code{<stdio.h>} library routines. @itemx @ @ @ @ struct awk_element *next; @itemx @ @ @ @ enum @{ @itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DEFAULT = 0,@ @ /* set by gawk */ -@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DELETE = 1@ @ @ @ /* set by extension if should be deleted */ +@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DELETE = 1@ @ @ @ /* set by extension */ @itemx @ @ @ @ @} flags; @itemx @ @ @ @ awk_value_t index; @itemx @ @ @ @ awk_value_t value; @@ -32713,8 +33116,8 @@ an extension to create a linked list of new elements that can then be added to an array in a loop that traverses the list. @item enum @{ @dots{} @} flags; -A set of flag values that convey information between @command{gawk} -and the extension. Currently there is only one: @code{AWK_ELEMENT_DELETE}. +A set of flag values that convey information between the extension +and @command{gawk}. Currently there is only one: @code{AWK_ELEMENT_DELETE}. Setting it causes @command{gawk} to delete the element from the original array upon release of the flattened array. @@ -32725,8 +33128,8 @@ The index and value of the element, respectively. @end table @item typedef struct awk_flat_array @{ -@itemx @ @ @ @ awk_const void *awk_const opaque1;@ @ @ @ /* private data for use by gawk */ -@itemx @ @ @ @ awk_const void *awk_const opaque2;@ @ @ @ /* private data for use by gawk */ +@itemx @ @ @ @ awk_const void *awk_const opaque1;@ @ @ @ /* for use by gawk */ +@itemx @ @ @ @ awk_const void *awk_const opaque2;@ @ @ @ /* for use by gawk */ @itemx @ @ @ @ awk_const size_t count;@ @ @ @ @ /* how many elements */ @itemx @ @ @ @ awk_element_t elements[1];@ @ /* will be extended */ @itemx @} awk_flat_array_t; @@ -32745,7 +33148,7 @@ The following functions relate to individual array elements. @table @code @item awk_bool_t get_element_count(awk_array_t a_cookie, size_t *count); -For the array represented by @code{a_cookie}, return in @code{*count} +For the array represented by @code{a_cookie}, place in @code{*count} the number of elements it contains. A subarray counts as a single element. Return false if there is an error. @@ -32765,7 +33168,8 @@ requires that you understand how such values are converted to strings (@pxref{Conversion}); thus using integral values is safest. As with @emph{all} strings passed into @code{gawk} from an extension, -the string value of @code{index} must come from the API-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()} and +the string value of @code{index} must come from @code{gawk_malloc()}, +@code{gawk_calloc()} or @code{gawk_realloc()}, and @command{gawk} releases the storage. @item awk_bool_t set_array_element(awk_array_t a_cookie, @@ -32792,7 +33196,7 @@ not exist in the array. The following functions relate to arrays as a whole: @table @code -@item awk_array_t create_array(); +@item awk_array_t create_array(void); Create a new array to which elements may be added. @xref{Creating Arrays}, for a discussion of how to create a new array and add elements to it. @@ -32809,7 +33213,13 @@ For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t} structure and fill it in. Set the pointer whose address is passed as @code{data} to point to this structure. Return true upon success, or false otherwise. -@xref{Flattening Arrays}, for a discussion of how to +@ifset FOR_PRINT +See the next section +@end ifset +@ifclear FOR_PRINT +@xref{Flattening Arrays}, +@end ifclear +for a discussion of how to flatten an array and work with it. @item awk_bool_t release_flattened_array(awk_array_t a_cookie, @@ -32829,6 +33239,7 @@ for C code to traverse the entire array. Test code in @file{extension/testext.c} does this, and also serves as a nice example showing how to use the APIs. +We walk through that part of the code one step at a time. First, the @command{gawk} script that drives the test extension: @example @@ -32967,8 +33378,7 @@ have this flag bit set: valrep2str(& flat_array->elements[i].value)); if (strcmp(value3.str_value.str, - flat_array->elements[i].index.str_value.str) - == 0) @{ + flat_array->elements[i].index.str_value.str) == 0) @{ flat_array->elements[i].flags |= AWK_ELEMENT_DELETE; printf("dump_array_and_delete: marking element \"%s\" " "for deletion\n", @@ -33072,7 +33482,9 @@ of the array cookie after the call to @code{set_element()}. The following C code is a simple test extension to create an array with two regular elements and with a subarray. The leading @code{#include} -directives and boilerplate variable declarations are omitted for brevity. +directives and boilerplate variable declarations +(@pxref{Extension API Boilerplate}) +are omitted for brevity. The first step is to create a new array and then install it in the symbol table: @@ -33318,7 +33730,7 @@ This variable is true if @command{gawk} was invoked with @option{--traditional} @end table The value of @code{do_lint} can change if @command{awk} code -modifies the @code{LINT} built-in variable (@pxref{Built-in Variables}). +modifies the @code{LINT} predefined variable (@pxref{Built-in Variables}). The others should not change during execution. @node Extension API Boilerplate @@ -33351,12 +33763,12 @@ static awk_bool_t (*init_func)(void) = NULL; /* OR: */ static awk_bool_t -init_my_module(void) +init_my_extension(void) @{ @dots{} @} -static awk_bool_t (*init_func)(void) = init_my_module; +static awk_bool_t (*init_func)(void) = init_my_extension; dl_load_func(func_table, some_name, "name_space_in_quotes") @end example @@ -33399,8 +33811,8 @@ It can then be looped over for multiple calls to @c Use @var{OR} for docbook @item static awk_bool_t (*init_func)(void) = NULL; @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @var{OR} -@itemx static awk_bool_t init_my_module(void) @{ @dots{} @} -@itemx static awk_bool_t (*init_func)(void) = init_my_module; +@itemx static awk_bool_t init_my_extension(void) @{ @dots{} @} +@itemx static awk_bool_t (*init_func)(void) = init_my_extension; If you need to do some initialization work, you should define a function that does it (creates variables, opens files, etc.) and then define the @code{init_func} pointer to point to your @@ -33467,8 +33879,8 @@ path with a list of directories to search for compiled extensions. Two useful functions that are not in @command{awk} are @code{chdir()} (so that an @command{awk} program can change its directory) and @code{stat()} (so that an @command{awk} program can gather information about a file). -This @value{SECTION} implements these functions for @command{gawk} -in an extension. +In order to illustrate the API in action, this @value{SECTION} implements +these functions for @command{gawk} in an extension. @menu * Internal File Description:: What the new functions will do. @@ -33490,8 +33902,7 @@ straightforward. It takes one argument, the new directory to change to: newdir = "/home/arnold/funstuff" ret = chdir(newdir) if (ret < 0) @{ - printf("could not change to %s: %s\n", - newdir, ERRNO) > "/dev/stderr" + printf("could not change to %s: %s\n", newdir, ERRNO) > "/dev/stderr" exit 1 @} @dots{} @@ -33679,7 +34090,7 @@ The second is a pointer to an @code{awk_value_t}, usually named @code{result}. @example -/* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ +/* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * do_chdir(int nargs, awk_value_t *result) @@ -33888,13 +34299,22 @@ for success: @} @} - array_set(array, "type", make_const_string(type, strlen(type), &tmp)); + array_set(array, "type", make_const_string(type, strlen(type), & tmp)); return 0; @} @end example -Finally, here is the @code{do_stat()} function. It starts with +The third argument to @code{stat()} was not discussed previously. This +argument is optional. If present, it causes @code{do_stat()} to use +the @code{stat()} system call instead of the @code{lstat()} system +call. This is done by using a function pointer: @code{statfunc}. +@code{statfunc} is initialized to point to @code{lstat()} (instead +of @code{stat()}) to get the file information, in case the file is a +symbolic link. However, if there were three arguments, @code{statfunc} +is set point to @code{stat()}, instead. + +Here is the @code{do_stat()} function. It starts with variable declarations and argument checking: @ignore @@ -33925,16 +34345,10 @@ do_stat(int nargs, awk_value_t *result) @} @end example -The third argument to @code{stat()} was not discussed previously. This argument -is optional. If present, it causes @code{stat()} to use the @code{stat()} -system call instead of the @code{lstat()} system call. - Then comes the actual work. First, the function gets the arguments. -Next, it gets the information for the file. -The code use @code{lstat()} (instead of @code{stat()}) -to get the file information, -in case the file is a symbolic link. -If there's an error, it sets @code{ERRNO} and returns: +Next, it gets the information for the file. If the called function +(@code{lstat()} or @code{stat()}) returns an error, the code sets +@code{ERRNO} and returns: @example /* file is first arg, array to hold results is second */ @@ -33963,7 +34377,7 @@ If there's an error, it sets @code{ERRNO} and returns: @end example The tedious work is done by @code{fill_stat_array()}, shown -earlier. When done, return the result from @code{fill_stat_array()}: +earlier. When done, the function returns the result from @code{fill_stat_array()}: @example ret = fill_stat_array(name, array, & sbuf); @@ -34026,7 +34440,7 @@ of the @file{gawkapi.h} header file, the following steps@footnote{In practice, you would probably want to use the GNU Autotools---Automake, Autoconf, Libtool, and @command{gettext}---to configure and build your libraries. Instructions for doing so are beyond -the scope of this @value{DOCUMENT}. @xref{gawkextlib}, for WWW links to +the scope of this @value{DOCUMENT}. @xref{gawkextlib}, for Internet links to the tools.} create a GNU/Linux shared library: @example @@ -34054,14 +34468,14 @@ BEGIN @{ for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] print "testff.awk modified:", - strftime("%m %d %y %H:%M:%S", data["mtime"]) + strftime("%m %d %Y %H:%M:%S", data["mtime"]) print "\nInfo for JUNK" ret = stat("JUNK", data) print "ret =", ret for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] - print "JUNK modified:", strftime("%m %d %y %H:%M:%S", data["mtime"]) + print "JUNK modified:", strftime("%m %d %Y %H:%M:%S", data["mtime"]) @} @end example @@ -34075,25 +34489,26 @@ $ @kbd{AWKLIBPATH=$PWD gawk -f testff.awk} @print{} Info for testff.awk @print{} ret = 0 @print{} data["blksize"] = 4096 -@print{} data["mtime"] = 1350838628 +@print{} data["devbsize"] = 512 +@print{} data["mtime"] = 1412004710 @print{} data["mode"] = 33204 @print{} data["type"] = file @print{} data["dev"] = 2053 @print{} data["gid"] = 1000 -@print{} data["ino"] = 1719496 -@print{} data["ctime"] = 1350838628 +@print{} data["ino"] = 10358899 +@print{} data["ctime"] = 1412004710 @print{} data["blocks"] = 8 @print{} data["nlink"] = 1 @print{} data["name"] = testff.awk -@print{} data["atime"] = 1350838632 +@print{} data["atime"] = 1412004716 @print{} data["pmode"] = -rw-rw-r-- -@print{} data["size"] = 662 +@print{} data["size"] = 666 @print{} data["uid"] = 1000 -@print{} testff.awk modified: 10 21 12 18:57:08 -@print{} +@print{} testff.awk modified: 09 29 2014 18:31:50 +@print{} @print{} Info for JUNK @print{} ret = -1 -@print{} JUNK modified: 01 01 70 02:00:00 +@print{} JUNK modified: 01 01 1970 02:00:00 @end example @node Extension Samples @@ -34118,9 +34533,9 @@ Others mainly provide example code that shows how to use the extension API. * Extension Sample Rev2way:: Reversing data sample two-way processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to @code{gettimeofday()} and @code{sleep()}. +* Extension Sample API Tests:: Tests for the API. @end menu @node Extension Sample File Functions @@ -34130,7 +34545,7 @@ The @code{filefuncs} extension provides three different functions, as follows: The usage is: @table @asis -@item @@load "filefuncs" +@item @code{@@load "filefuncs"} This is how you load the extension. @cindex @code{chdir()} extension function @@ -34193,7 +34608,7 @@ Not all systems support all file types. @tab All @itemx @code{result = fts(pathlist, flags, filedata)} Walk the file trees provided in @code{pathlist} and fill in the @code{filedata} array as described below. @code{flags} is the bitwise -OR of several predefined constant values, also described below. +OR of several predefined values, also described below. Return zero if there were no errors, otherwise return @minus{}1. @end table @@ -34238,10 +34653,10 @@ Immediately follow a symbolic link named in @code{pathlist}, whether or not @code{FTS_LOGICAL} is set. @item FTS_SEEDOT -By default, the @code{fts()} routines do not return entries for @file{.} (dot) -and @file{..} (dot-dot). This option causes entries for dot-dot to also -be included. (The extension always includes an entry for dot, -see below.) +By default, the C library @code{fts()} routines do not return entries for +@file{.} (dot) and @file{..} (dot-dot). This option causes entries for +dot-dot to also be included. (The extension always includes an entry +for dot, see below.) @item FTS_XDEV During a traversal, do not cross onto a different mounted filesystem. @@ -34295,8 +34710,8 @@ Otherwise it returns @minus{}1. @quotation NOTE The @code{fts()} extension does not exactly mimic the interface of the C library @code{fts()} routines, choosing instead to -provide an interface that is based on associative arrays, which should -be more comfortable to use from an @command{awk} program. This includes the +provide an interface that is based on associative arrays, which is +more comfortable to use from an @command{awk} program. This includes the lack of a comparison function, since @command{gawk} already provides powerful array sorting facilities. While an @code{fts_read()}-like interface could have been provided, this felt less natural than simply @@ -34304,7 +34719,8 @@ creating a multidimensional array to represent the file hierarchy and its information. @end quotation -See @file{test/fts.awk} in the @command{gawk} distribution for an example. +See @file{test/fts.awk} in the @command{gawk} distribution for an example +use of the @code{fts()} extension function. @node Extension Sample Fnmatch @subsection Interface To @code{fnmatch()} @@ -34508,11 +34924,11 @@ The record consists of three fields. The first two are the inode number and the @value{FN}, separated by a forward slash character. On systems where the directory entry contains the file type, the record has a third field (also separated by a slash) which is a single letter -indicating the type of the file. The letters are file types are shown -in @ref{table-readdir-file-types}. +indicating the type of the file. The letters and their corresponding file +types are shown in @ref{table-readdir-file-types}. @float Table,table-readdir-file-types -@caption{File Types Returned By @code{readdir()}} +@caption{File Types Returned By The @code{readdir} Extension} @multitable @columnfractions .1 .9 @headitem Letter @tab File Type @item @code{b} @tab Block device @@ -34604,6 +35020,9 @@ The @code{rwarray} extension adds two functions, named @code{writea()} and @code{reada()}, as follows: @table @code +@item @@load "rwarray" +This is how you load the extension. + @cindex @code{writea()} extension function @item ret = writea(file, array) This function takes a string argument, which is the name of the file @@ -34679,17 +35098,6 @@ if (contents == "" && ERRNO != "") @{ @} @end example -@node Extension Sample API Tests -@subsection API Tests -@cindex @code{testext} extension - -The @code{testext} extension exercises parts of the extension API that -are not tested by the other samples. The @file{extension/testext.c} -file contains both the C code for the extension and @command{awk} -test code inside C comments that run the tests. The testing framework -extracts the @command{awk} code and runs the tests. See the source file -for more information. - @node Extension Sample Time @subsection Extension Time Functions @@ -34720,6 +35128,17 @@ Implementation details: depending on platform availability, this function tries to use @code{nanosleep()} or @code{select()} to implement the delay. @end table +@node Extension Sample API Tests +@subsection API Tests +@cindex @code{testext} extension + +The @code{testext} extension exercises parts of the extension API that +are not tested by the other samples. The @file{extension/testext.c} +file contains both the C code for the extension and @command{awk} +test code inside C comments that run the tests. The testing framework +extracts the @command{awk} code and runs the tests. See the source file +for more information. + @node gawkextlib @section The @code{gawkextlib} Project @cindex @code{gawkextlib} @@ -34735,8 +35154,7 @@ As of this writing, there are five extensions: @itemize @value{BULLET} @item -XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} -XML parsing library. +GD graphics library extension. @item PDF extension. @@ -34745,17 +35163,14 @@ PDF extension. PostgreSQL extension. @item -GD graphics library extension. - -@item MPFR library extension. This provides access to a number of MPFR functions which @command{gawk}'s native MPFR support does not. -@end itemize -The @code{time} extension described earlier (@pxref{Extension Sample -Time}) was originally from this project but has been moved in to the -main @command{gawk} distribution. +@item +XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} +XML parsing library. +@end itemize @cindex @command{git} utility You can check out the code for the @code{gawkextlib} project @@ -34832,7 +35247,7 @@ certain tasks. @item One of these tasks is to ``register'' the name and implementation of -a new @command{awk}-level function with @command{gawk}. The implementation +new @command{awk}-level functions with @command{gawk}. The implementation takes the form of a C function pointer with a defined signature. By convention, implementation functions are named @code{do_@var{XXXX}()} for some @command{awk}-level function @code{@var{XXXX}()}. @@ -34846,6 +35261,9 @@ API function pointers are provided for the following kinds of operations: @itemize @value{BULLET} @item +Allocating, reallocating, and releasing memory. + +@item Registration functions. You may register extension functions, exit callbacks, @@ -34869,9 +35287,6 @@ Symbol table access: retrieving a global variable, creating one, or changing one. @item -Allocating, reallocating, and releasing memory. - -@item Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -34883,7 +35298,7 @@ getting the count of elements in an array; creating a new array; clearing an array; and -flattening an array for easy C style looping over all its indices and elements +flattening an array for easy C style looping over all its indices and elements. @end itemize @item @@ -34903,7 +35318,7 @@ treated as read-only by the extension. @item @emph{All} memory passed from an extension to @command{gawk} must come from the API's memory allocation functions. @command{gawk} takes responsibility for -the memory and will release it when appropriate. +the memory and releases it when appropriate. @item The API provides information about the running version of @command{gawk} so @@ -34920,7 +35335,7 @@ The @command{gawk} distribution includes a number of small but useful sample extensions. The @code{gawkextlib} project includes several more, larger, extensions. If you wish to write an extension and contribute it to the community of @command{gawk} users, the @code{gawkextlib} project -should be the place to do so. +is the place to do so. @end itemize @@ -35002,7 +35417,7 @@ which follows the POSIX specification. Many long-time @command{awk} users learned @command{awk} programming with the original @command{awk} implementation in Version 7 Unix. (This implementation was the basis for @command{awk} in Berkeley Unix, through 4.3-Reno. Subsequent versions -of Berkeley Unix, and some systems derived from 4.4BSD-Lite, used various +of Berkeley Unix, and, for a while, some systems derived from 4.4BSD-Lite, used various versions of @command{gawk} for their @command{awk}.) This @value{CHAPTER} briefly describes the evolution of the @command{awk} language, with cross-references to other parts of the @value{DOCUMENT} where you can @@ -35075,7 +35490,7 @@ The built-in functions @code{close()} and @code{system()} @item The @code{ARGC}, @code{ARGV}, @code{FNR}, @code{RLENGTH}, @code{RSTART}, -and @code{SUBSEP} built-in variables (@pxref{Built-in Variables}). +and @code{SUBSEP} predefined variables (@pxref{Built-in Variables}). @item Assignable @code{$0} (@pxref{Changing Fields}). @@ -35106,14 +35521,11 @@ of @code{FS}. @item Dynamic regexps as operands of the @samp{~} and @samp{!~} operators -(@pxref{Regexp Usage}). +(@pxref{Computed Regexps}). @item The escape sequences @samp{\b}, @samp{\f}, and @samp{\r} (@pxref{Escape Sequences}). -(Some vendors have updated their old versions of @command{awk} to -recognize @samp{\b}, @samp{\f}, and @samp{\r}, but this is not -something you can rely on.) @item Redirection of input for the @code{getline} function @@ -35152,7 +35564,7 @@ The @option{-v} option for assigning variables before program execution begins @c GNU, Bell Laboratories & MKS together @item -The @option{--} option for terminating command-line options. +The @option{--} signal for terminating command-line options. @item The @samp{\a}, @samp{\v}, and @samp{\x} escape sequences @@ -35169,13 +35581,13 @@ for case translation (@pxref{String Functions}). @item -A cleaner specification for the @samp{%c} format-control letter in the +A cleaner specification for the @code{%c} format-control letter in the @code{printf} function (@pxref{Control Letters}). @item The ability to dynamically pass the field width and precision (@code{"%*.*d"}) -in the argument list of the @code{printf} function +in the argument list of @code{printf} and @code{sprintf()} (@pxref{Control Letters}). @item @@ -35210,8 +35622,8 @@ The concept of a numeric string and tighter comparison rules to go with it (@pxref{Typing and Comparison}). @item -The use of built-in variables as function parameter names is forbidden -(@pxref{Definition Syntax}. +The use of predefined variables as function parameter names is forbidden +(@pxref{Definition Syntax}). @item More complete documentation of many of the previously undocumented @@ -35306,7 +35718,7 @@ in the current version of @command{gawk}. @itemize @value{BULLET} @item -Additional built-in variables: +Additional predefined variables: @itemize @value{MINUS} @item @@ -35390,14 +35802,6 @@ The @code{BEGINFILE} and @code{ENDFILE} special patterns. (@pxref{BEGINFILE/ENDFILE}). @item -The ability to delete all of an array at once with @samp{delete @var{array}} -(@pxref{Delete}). - -@item -The @code{nextfile} statement -(@pxref{Nextfile Statement}). - -@item The @code{switch} statement (@pxref{Switch Statement}). @end itemize @@ -35412,7 +35816,7 @@ of a two-way pipe to a coprocess (@pxref{Two-way I/O}). @item -POSIX compliance for @code{gsub()} and @code{sub()}. +POSIX compliance for @code{gsub()} and @code{sub()} with @option{--posix}. @item The @code{length()} function accepts an array argument @@ -35440,6 +35844,20 @@ Additional functions only in @command{gawk}: @itemize @value{MINUS} @item +The @code{gensub()}, @code{patsplit()}, and @code{strtonum()} functions +for more powerful text manipulation +(@pxref{String Functions}). + +@item +The @code{asort()} and @code{asorti()} functions for sorting arrays +(@pxref{Array Sorting}). + +@item +The @code{mktime()}, @code{systime()}, and @code{strftime()} +functions for working with timestamps +(@pxref{Time Functions}). + +@item The @code{and()}, @code{compl()}, @@ -35453,30 +35871,15 @@ functions for bit manipulation @c In 4.1, and(), or() and xor() grew the ability to take > 2 arguments @item -The @code{asort()} and @code{asorti()} functions for sorting arrays -(@pxref{Array Sorting}). +The @code{isarray()} function to check if a variable is an array or not +(@pxref{Type Functions}). @item The @code{bindtextdomain()}, @code{dcgettext()} and @code{dcngettext()} functions for internationalization (@pxref{Programmer i18n}). - -@item -The @code{fflush()} function from BWK @command{awk} -(@pxref{I/O Functions}). - -@item -The @code{gensub()}, @code{patsplit()}, and @code{strtonum()} functions -for more powerful text manipulation -(@pxref{String Functions}). - -@item -The @code{mktime()}, @code{systime()}, and @code{strftime()} -functions for working with timestamps -(@pxref{Time Functions}). @end itemize - @item Changes and/or additions in the command-line options: @@ -35599,7 +36002,7 @@ GCC for VAX and Alpha has not been tested for a while. @item Support for the following obsolete systems was removed from the code -and the documentation for @command{gawk} @value{PVERSION} 4.1: +for @command{gawk} @value{PVERSION} 4.1: @c nested table @itemize @value{MINUS} @@ -36203,7 +36606,7 @@ The @option{-l} and @option{--load} options load compiled dynamic extensions. The @option{-M} and @option{--bignum} options enable MPFR. @item -The @option{-o} only does pretty-printing. +The @option{-o} option only does pretty-printing. @item The @option{-p} option is used for profiling. @@ -36236,33 +36639,29 @@ The dynamic extension interface was completely redone @cindex extensions, Brian Kernighan's @command{awk} @cindex extensions, @command{mawk} -This @value{SECTION} summarizes the common extensions supported +The following table summarizes the common extensions supported by @command{gawk}, Brian Kernighan's @command{awk}, and @command{mawk}, the three most widely-used freely available versions of @command{awk} (@pxref{Other Versions}). -@multitable {@file{/dev/stderr} special file} {BWK Awk} {Mawk} {GNU Awk} -@headitem Feature @tab BWK Awk @tab Mawk @tab GNU Awk -@item @samp{\x} Escape sequence @tab X @tab X @tab X -@item @code{FS} as null string @tab X @tab X @tab X -@item @file{/dev/stdin} special file @tab X @tab X @tab X -@item @file{/dev/stdout} special file @tab X @tab X @tab X -@item @file{/dev/stderr} special file @tab X @tab X @tab X -@item @code{delete} without subscript @tab X @tab X @tab X -@item @code{fflush()} function @tab X @tab X @tab X -@item @code{length()} of an array @tab X @tab X @tab X -@item @code{nextfile} statement @tab X @tab X @tab X -@item @code{**} and @code{**=} operators @tab X @tab @tab X -@item @code{func} keyword @tab X @tab @tab X -@item @code{BINMODE} variable @tab @tab X @tab X -@item @code{RS} as regexp @tab @tab X @tab X -@item Time related functions @tab @tab X @tab X +@multitable {@file{/dev/stderr} special file} {BWK Awk} {Mawk} {GNU Awk} {Now standard} +@headitem Feature @tab BWK Awk @tab Mawk @tab GNU Awk @tab Now standard +@item @samp{\x} Escape sequence @tab X @tab X @tab X @tab +@item @code{FS} as null string @tab X @tab X @tab X @tab +@item @file{/dev/stdin} special file @tab X @tab X @tab X @tab +@item @file{/dev/stdout} special file @tab X @tab X @tab X @tab +@item @file{/dev/stderr} special file @tab X @tab X @tab X @tab +@item @code{delete} without subscript @tab X @tab X @tab X @tab X +@item @code{fflush()} function @tab X @tab X @tab X @tab X +@item @code{length()} of an array @tab X @tab X @tab X @tab +@item @code{nextfile} statement @tab X @tab X @tab X @tab X +@item @code{**} and @code{**=} operators @tab X @tab @tab X @tab +@item @code{func} keyword @tab X @tab @tab X @tab +@item @code{BINMODE} variable @tab @tab X @tab X @tab +@item @code{RS} as regexp @tab @tab X @tab X @tab +@item Time related functions @tab @tab X @tab X @tab @end multitable -(Technically speaking, as of late 2012, @code{fflush()}, @samp{delete @var{array}}, -and @code{nextfile} are no longer extensions, since they have been added -to POSIX.) - @node Ranges and Locales @appendixsec Regexp Ranges and Locales: A Long Sad Story @@ -36299,6 +36698,7 @@ In the @code{"C"} and @code{"POSIX"} locales, a range expression like But outside those locales, the ordering was defined to be based on @dfn{collation order}. +What does that mean? In many locales, @samp{A} and @samp{a} are both less than @samp{B}. In other words, these locales sort characters in dictionary order, and @samp{[a-dx-z]} is typically not equivalent to @samp{[abcdxyz]}; @@ -36306,7 +36706,7 @@ instead it might be equivalent to @samp{[ABCXYabcdxyz]}, for example. This point needs to be emphasized: Much literature teaches that you should use @samp{[a-z]} to match a lowercase character. But on systems with -non-ASCII locales, this also matched all of the uppercase characters +non-ASCII locales, this also matches all of the uppercase characters except @samp{A} or @samp{Z}! This was a continuous cause of confusion, even well into the twenty-first century. @@ -36496,7 +36896,7 @@ the various PC platforms. @cindex Zoulas, Christos Christos Zoulas provided the @code{extension()} -built-in function for dynamically adding new modules. +built-in function for dynamically adding new functions. (This was obsoleted at @command{gawk} 4.1.) @item @@ -36612,6 +37012,11 @@ The development of the extension API first released with Arnold Robbins and Andrew Schorr, with notable contributions from the rest of the development team. +@cindex Malmberg, John E. +@item +John Malmberg contributed significant improvements to the +OpenVMS port and the related documentation. + @item @cindex Colombo, Antonio Antonio Giovanni Colombo rewrote a number of examples in the early @@ -36673,7 +37078,7 @@ various platforms that are supported by the developers. The primary developer supports GNU/Linux (and Unix), whereas the other ports are contributed. @xref{Bugs}, -for the electronic mail addresses of the people who did +for the electronic mail addresses of the people who maintain the respective ports. @menu @@ -36948,6 +37353,12 @@ The source code, manual pages, and infrastructure files for the sample extensions included with @command{gawk}. @xref{Dynamic Extensions}, for more information. +@item extras/* +Additional non-essential files. Currently, this directory contains some shell +startup files to be installed in @file{/etc/profile.d} to aid in manipulating +the @env{AWKPATH} and @env{AWKLIBPATH} environment variables. +@xref{Shell Startup Files}, for more information. + @item posix/* Files needed for building @command{gawk} on POSIX-compliant systems. @@ -36980,6 +37391,7 @@ to configure @command{gawk} for your system yourself. @menu * Quick Installation:: Compiling @command{gawk} under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. @end menu @@ -36992,11 +37404,10 @@ Unix-derived systems, GNU/Linux, BSD-based systems, and the Cygwin environment for MS-Windows. After you have extracted the @command{gawk} distribution, @command{cd} -to @file{gawk-@value{VERSION}.@value{PATCHLEVEL}}. Like most GNU software, -@command{gawk} is configured -automatically for your system by running the @command{configure} program. -This program is a Bourne shell script that is generated automatically using -GNU Autoconf. +to @file{gawk-@value{VERSION}.@value{PATCHLEVEL}}. As with most GNU +software, you configure @command{gawk} for your system by running the +@command{configure} program. This program is a Bourne shell script that +is generated automatically using GNU Autoconf. @ifnotinfo (The Autoconf software is described fully in @@ -37061,6 +37472,44 @@ is likely that you will be asked for your password, and you will have to have been set up previously as a user who is allowed to run the @command{sudo} command. +@node Shell Startup Files +@appendixsubsec Shell Startup Files + +The distribution contains shell startup files @file{gawk.sh} and +@file{gawk.csh} containing functions to aid in manipulating +the @env{AWKPATH} and @env{AWKLIBPATH} environment variables. +On a Fedora system, these files should be installed in @file{/etc/profile.d}; +on other platforms, the appropriate location may be different. + +@table @command + +@cindex @command{gawkpath_default} shell function +@item gawkpath_default +Reset the @env{AWKPATH} environment variable to its default value. + +@cindex @command{gawkpath_prepend} shell function +@item gawkpath_prepend +Add the argument to the front of the @env{AWKPATH} environment variable. + +@cindex @command{gawkpath_append} shell function +@item gawkpath_append +Add the argument to the end of the @env{AWKPATH} environment variable. + +@cindex @command{gawklibpath_default} shell function +@item gawklibpath_default +Reset the @env{AWKLIBPATH} environment variable to its default value. + +@cindex @command{gawklibpath_prepend} shell function +@item gawklibpath_prepend +Add the argument to the front of the @env{AWKLIBPATH} environment variable. + +@cindex @command{gawklibpath_append} shell function +@item gawklibpath_append +Add the argument to the end of the @env{AWKLIBPATH} environment variable. + +@end table + + @node Additional Configuration Options @appendixsubsec Additional Configuration Options @cindex @command{gawk}, configuring, options @@ -37091,8 +37540,8 @@ Similarly, setting the @code{LINT} variable has no effect on the running @command{awk} program. When used with GCC's automatic dead-code-elimination, this option -cuts almost 200K bytes off the size of the @command{gawk} -executable on GNU/Linux x86 systems. Results on other systems and +cuts almost 23K bytes off the size of the @command{gawk} +executable on GNU/Linux x86_64 systems. Results on other systems and with other compilers are likely to vary. Using this option may bring you some slight performance improvement. @@ -37185,7 +37634,8 @@ various non-Unix systems. @cindex PC operating systems@comma{} @command{gawk} on, installing @cindex operating systems, PC@comma{} @command{gawk} on, installing -This @value{SECTION} covers installation and usage of @command{gawk} on x86 machines +This @value{SECTION} covers installation and usage of @command{gawk} +on Intel architecture machines @ifclear FOR_PRINT running MS-DOS, any version of MS-Windows, or OS/2. @end ifclear @@ -37287,7 +37737,8 @@ MS-DOS and Windows32 versions. A list of targets is printed if the build @command{gawk} using the DJGPP tools, enter @samp{make djgpp}. (The DJGPP tools needed for the build may be found at @uref{ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/}.) To build a -native MS-Windows binary of @command{gawk}, type @samp{make mingw32}. +native MS-Windows binary of @command{gawk} using the MinGW tools, +type @samp{make mingw32}. @ifclear FOR_PRINT @cindex compiling @command{gawk} with EMX for OS/2 @@ -37410,15 +37861,14 @@ EMX (OS/2 only) supports at least the @samp{|&} operator. @cindex search paths, for source files @cindex @command{gawk}, MS-DOS version of @cindex @command{gawk}, MS-Windows version of -@cindex @code{;} (semicolon), @code{AWKPATH} variable and -@cindex semicolon (@code{;}), @code{AWKPATH} variable and +@cindex @code{;} (semicolon), @env{AWKPATH} variable and +@cindex semicolon (@code{;}), @env{AWKPATH} variable and @cindex @env{AWKPATH} environment variable The MS-DOS and MS-Windows versions of @command{gawk} search for program files as described in @ref{AWKPATH Variable}. However, semicolons (rather than colons) separate elements in the @env{AWKPATH} variable. If @env{AWKPATH} is not set or is empty, then the default -search path for MS-Windows and MS-DOS versions is -@samp{@w{.;c:/lib/awk;c:/gnu/lib/awk}}. +search path is @samp{@w{.;c:/lib/awk;c:/gnu/lib/awk}}. @ifclear FOR_PRINT @cindex @command{gawk}, OS/2 version of @@ -37463,12 +37913,12 @@ allows control over these translations and is interpreted as follows: @itemize @value{BULLET} @item -If @code{BINMODE} is @code{"r"}, or one, +If @code{BINMODE} is @code{"r"} or one, then binary mode is set on read (i.e., no translations on reads). @item -If @code{BINMODE} is @code{"w"}, or two, +If @code{BINMODE} is @code{"w"} or two, then binary mode is set on write (i.e., no translations on writes). @@ -37556,7 +38006,7 @@ same as for a Unix system: tar -xvpzf gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz cd gawk-@value{VERSION}.@value{PATCHLEVEL} ./configure -make +make && make check @end example When compared to GNU/Linux on the same system, the @samp{configure} @@ -37572,10 +38022,10 @@ need to use the @code{BINMODE} variable. This can cause problems with other Unix-like components that have been ported to MS-Windows that expect @command{gawk} to do automatic -translation of @code{"\r\n"}, since it won't. Caveat Emptor! +translation of @code{"\r\n"}, since it won't. @node VMS Installation -@appendixsubsec How to Compile and Install @command{gawk} on Vax/VMS and OpenVMS +@appendixsubsec Compiling and Installing @command{gawk} on Vax/VMS and OpenVMS @c based on material from Pat Rankin <rankin@eql.caltech.edu> @c now rankin@pactechdata.com @@ -37680,7 +38130,7 @@ For VAX: @end example Compile time macros need to be defined before the first VMS-supplied -header file is included. +header file is included, as follows: @example #if (__CRTL_VER >= 70200000) && !defined (__VAX) @@ -37696,6 +38146,11 @@ header file is included. #endif @end example +If you are writing your own extensions to run on VMS, you must supply these +definitions yourself. The @file{config.h} file created when building @command{gawk} +on VMS does this for you; if instead you use that file or a similar one, then you +must remember to include it before any VMS-supplied header files. + @node VMS Installation Details @appendixsubsubsec Installing @command{gawk} on VMS @@ -37792,12 +38247,12 @@ other dash-type options (or multiple parameters such as @value{DF}s to process) are present, there is no ambiguity and @option{--} can be omitted. @cindex exit status, of VMS -The @code{exit} value is a Unix-style value and is encoded to a VMS exit +The @code{exit} value is a Unix-style value and is encoded into a VMS exit status value when the program exits. The VMS severity bits will be set based on the @code{exit} value. A failure is indicated by 1 and VMS sets the @code{ERROR} status. -A fatal error is indicated by 2 and VMS will set the @code{FATAL} status. +A fatal error is indicated by 2 and VMS sets the @code{FATAL} status. All other values will have the @code{SUCCESS} status. The exit value is encoded to comply with VMS coding standards and will have the @code{C_FACILITY_NO} of @code{0x350000} with the constant @code{0xA000} @@ -37813,7 +38268,7 @@ unix_status = (vms_status .and. &x7f8) / 8 A C program that uses @code{exec()} to call @command{gawk} will get the original Unix-style exit value. -Older versions of @command{gawk} treated a Unix exit code 0 as 1, a failure +Older versions of @command{gawk} for VMS treated a Unix exit code 0 as 1, a failure as 2, a fatal error as 4, and passed all the other numbers through. This violated the VMS exit status coding requirements. @@ -37847,8 +38302,8 @@ See @w{@uref{https://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/}.} The normal build procedure for @command{gawk} produces a program that is suitable for use with GNV. -The @file{vms/gawk_build_steps.txt} in the source documents the procedure -for building a VMS PCSI kit that is compatible with GNV. +The file @file{vms/gawk_build_steps.txt} in the distribution documents +the procedure for building a VMS PCSI kit that is compatible with GNV. @ignore @c The VMS POSIX product, also known as POSIX for OpenVMS, is long defunct @@ -37920,8 +38375,8 @@ If you have problems with @command{gawk} or think that you have found a bug, please report it to the developers; we cannot promise to do anything but we might well want to fix it. -Before reporting a bug, make sure you have actually found a real bug. -Carefully reread the documentation and see if it really says you can do +Before reporting a bug, please make sure you have really found a genuine bug. +Carefully reread the documentation and see if it says you can do what you're trying to do. If it's not clear whether you should be able to do something or not, report that too; it's a bug in the documentation! @@ -37939,17 +38394,15 @@ You can get this information with the command @samp{gawk --version}. @cindex @code{bug-gawk@@gnu.org} bug reporting address @cindex email address for bug reports, @code{bug-gawk@@gnu.org} @cindex bug reports, email address, @code{bug-gawk@@gnu.org} -Once you have a precise problem, send email to +Once you have a precise problem description, send email to @EMAIL{bug-gawk@@gnu.org,bug-gawk at gnu dot org}. -@cindex Robbins, Arnold The @command{gawk} maintainers subscribe to this address and thus they will receive your bug report. -If necessary, the primary maintainer can be reached directly at -@EMAIL{arnold@@skeeve.com,arnold at skeeve dot com}. -The bug reporting address is preferred since the +Although you can send mail to the maintainers directly, +the bug reporting address is preferred since the email list is archived at the GNU Project. -@emph{All email should be in English. This is the only language +@emph{All email must be in English. This is the only language understood in common by all the maintainers.} @cindex @code{comp.lang.awk} newsgroup @@ -37958,7 +38411,7 @@ Do @emph{not} try to report bugs in @command{gawk} by posting to the Usenet/Internet newsgroup @code{comp.lang.awk}. While the @command{gawk} developers do occasionally read this newsgroup, there is no guarantee that we will see your posting. The steps described -above are the official recognized ways for reporting bugs. +above are the only official recognized way for reporting bugs. Really. @end quotation @@ -37970,35 +38423,34 @@ bug reporting system, @emph{please} also send a copy to This is for two reasons. First, while some distributions forward bug reports ``upstream'' to the GNU mailing list, many don't, so there is a good -chance that the @command{gawk} maintainer won't even see the bug report! Second, +chance that the @command{gawk} maintainers won't even see the bug report! Second, mail to the GNU list is archived, and having everything at the GNU project -keeps things self-contained and not dependant on other web sites. +keeps things self-contained and not dependant on other organizations. @end quotation Non-bug suggestions are always welcome as well. If you have questions about things that are unclear in the documentation or are just obscure -features, ask me; I will try to help you out, although I -may not have the time to fix the problem. You can send me electronic -mail at the Internet address noted previously. - -If you find bugs in one of the non-Unix ports of @command{gawk}, please send -an electronic mail message to the person who maintains that port. They -are named in the following list, as well as in the @file{README} file -in the @command{gawk} distribution. Information in the @file{README} -file should be considered authoritative if it conflicts with this -@value{DOCUMENT}. +features, ask on the bug list; we will try to help you out if we can. -The people maintaining the non-Unix ports of @command{gawk} are -as follows: +If you find bugs in one of the non-Unix ports of @command{gawk}, please +send an electronic mail message to the bug list, with a copy to the +person who maintains that port. They are named in the following list, +as well as in the @file{README} file in the @command{gawk} distribution. +Information in the @file{README} file should be considered authoritative +if it conflicts with this @value{DOCUMENT}. + +The people maintaining the various @command{gawk} ports are: @c put the index entries outside the table, for docbook -@cindex Deifik, Scott -@cindex Zaretskii, Eli @cindex Buening, Andreas -@cindex Rankin, Pat +@cindex Deifik, Scott @cindex Malmberg, John @cindex Pitts, Dave +@cindex Robbins, Arnold +@cindex Zaretskii, Eli @multitable {MS-Windows with MinGW} {123456789012345678901234567890123456789001234567890} +@item Unix and POSIX systems @tab Arnold Robbins, @EMAIL{arnold@@skeeve.com,arnold at skeeve dot com}. + @item MS-DOS with DJGPP @tab Scott Deifik, @EMAIL{scottd.mail@@sbcglobal.net,scottd dot mail at sbcglobal dot net}. @item MS-Windows with MinGW @tab Eli Zaretskii, @EMAIL{eliz@@gnu.org,eliz at gnu dot org}. @@ -38007,8 +38459,7 @@ as follows: @c OS/2 is not mentioned anywhere else in the print version though. @item OS/2 @tab Andreas Buening, @EMAIL{andreas.buening@@nexgo.de,andreas dot buening at nexgo dot de}. -@item VMS @tab Pat Rankin, @EMAIL{r.pat.rankin@@gmail.com,r.pat.rankin at gmail.com}, and -John Malmberg, @EMAIL{wb8tyw@@qsl.net,wb8tyw at qsl.net}. +@item VMS @tab John Malmberg, @EMAIL{wb8tyw@@qsl.net,wb8tyw at qsl.net}. @item z/OS (OS/390) @tab Dave Pitts, @EMAIL{dpitts@@cozx.com,dpitts at cozx dot com}. @end multitable @@ -38041,15 +38492,11 @@ Date: Wed, 4 Sep 1996 08:11:48 -0700 (PDT) @docbook <blockquote><attribution>Michael Brennan</attribution> -<literallayout> -<emphasis>It's kind of fun to put comments like this in your awk code.</emphasis> - <literal>// Do C++ comments work? answer: yes! of course</literal> -</literallayout> +<literallayout><emphasis>It's kind of fun to put comments like this in your awk code.</emphasis> + <literal>// Do C++ comments work? answer: yes! of course</literal></literallayout> </blockquote> @end docbook - - There are a number of other freely available @command{awk} implementations. This @value{SECTION} briefly describes where to get them: @@ -38154,7 +38601,7 @@ since approximately 2003. @item @command{pawk} Nelson H.F.@: Beebe at the University of Utah has modified BWK @command{awk} to provide timing and profiling information. -It is different from @command{gawk} with the @option{--profile} option. +It is different from @command{gawk} with the @option{--profile} option (@pxref{Profiling}), in that it uses CPU-based profiling, not line-count profiling. You may find it at either @@ -38179,7 +38626,7 @@ information, see the @uref{http://busybox.net, project's home page}. The versions of @command{awk} in @file{/usr/xpg4/bin} and @file{/usr/xpg6/bin} on Solaris are more-or-less POSIX-compliant. They are based on the @command{awk} from Mortice Kern Systems for PCs. -This author was able to make this code compile and work under GNU/Linux +We were able to make this code compile and work under GNU/Linux with 1--2 hours of work. Making it more generally portable (using GNU Autoconf and/or Automake) would take more work, and this has not been done, at least to our knowledge. @@ -38406,7 +38853,7 @@ make it possible to include them: @enumerate 1 @item Before building the new feature into @command{gawk} itself, -consider writing it as an extension module +consider writing it as an extension (@pxref{Dynamic Extensions}). If that's not possible, continue with the rest of the steps in this list. @@ -38651,7 +39098,7 @@ and @item Be willing to continue to maintain the port. Non-Unix operating systems are supported by volunteers who maintain -the code needed to compile and run @command{gawk} on their systems. If noone +the code needed to compile and run @command{gawk} on their systems. If no-one volunteers to maintain a port, it becomes unsupported and it may be necessary to remove it from the distribution. @@ -39137,7 +39584,7 @@ Pat Rankin suggested the solution that was adopted. @appendixsubsec Other Design Decisions As an arbitrary design decision, extensions can read the values of -built-in variables and arrays (such as @code{ARGV} and @code{FS}), but cannot +predefined variables and arrays (such as @code{ARGV} and @code{FS}), but cannot change them, with the exception of @code{PROCINFO}. The reason for this is to prevent an extension function from affecting @@ -39631,6 +40078,11 @@ originally written by Steven R.@: Bourne at Bell Laboratories. Many shells (Bash, @command{ksh}, @command{pdksh}, @command{zsh}) are generally upwardly compatible with the Bourne shell. +@item Braces +The characters @samp{@{} and @samp{@}}. Braces are used in +@command{awk} for delimiting actions, compound statements, and function +bodies. + @item Built-in Function The @command{awk} language provides built-in functions that perform various numerical, I/O-related, and string computations. Examples are @@ -39676,11 +40128,6 @@ are the variables that have special meaning to @command{gawk}. Changing some of them affects @command{awk}'s running environment. (@xref{Built-in Variables}.) -@item Braces -The characters @samp{@{} and @samp{@}}. Braces are used in -@command{awk} for delimiting actions, compound statements, and function -bodies. - @item C The system programming language that most GNU software is written in. The @command{awk} programming language has C-like syntax, and this @value{DOCUMENT} @@ -39878,11 +40325,11 @@ See ``Free Documentation License.'' @item Field When @command{awk} reads an input record, it splits the record into pieces separated by whitespace (or by a separator regexp that you can -change by setting the built-in variable @code{FS}). Such pieces are +change by setting the predefined variable @code{FS}). Such pieces are called fields. If the pieces are of fixed length, you can use the built-in variable @code{FIELDWIDTHS} to describe their lengths. If you wish to specify the contents of fields instead of the field -separator, you can use the built-in variable @code{FPAT} to do so. +separator, you can use the predefined variable @code{FPAT} to do so. (@xref{Field Separators}, @ref{Constant Size}, and @@ -39901,7 +40348,7 @@ See also ``Double Precision'' and ``Single Precision.'' Format strings control the appearance of output in the @code{strftime()} and @code{sprintf()} functions, and in the @code{printf} statement as well. Also, data conversions from numbers to strings -are controlled by the format strings contained in the built-in variables +are controlled by the format strings contained in the predefined variables @code{CONVFMT} and @code{OFMT}. (@xref{Control Letters}.) @item Free Documentation License @@ -41580,6 +42027,7 @@ Consistency issues: Use --foo, not -Wfoo when describing long options Use "Bell Laboratories", but not "Bell Labs". Use "behavior" instead of "behaviour". + Use "coprocess" instead of "co-process". Use "zeros" instead of "zeroes". Use "nonzero" not "non-zero". Use "runtime" not "run time" or "run-time". @@ -41684,4 +42132,4 @@ But to use it you have to say which sorta sucks. TODO: ------ +Check that all dark corners are indexed properly. diff --git a/doc/gawktexi.in b/doc/gawktexi.in index 004157f0..c06bca82 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -32,13 +32,11 @@ @ifnotdocbook @set BULLET @bullet{} @set MINUS @minus{} -@set NUL @sc{nul} @end ifnotdocbook @ifdocbook @set BULLET @set MINUS -@set NUL NUL @end ifdocbook @set xref-automatic-section-title @@ -48,11 +46,16 @@ @c applies to and all the info about who's publishing this edition @c These apply across the board. -@set UPDATE-MONTH August, 2014 +@set UPDATE-MONTH September, 2014 @set VERSION 4.1 -@set PATCHLEVEL 1 +@set PATCHLEVEL 2 +@ifset FOR_PRINT +@set TITLE Effective AWK Programming +@end ifset +@ifclear FOR_PRINT @set TITLE GAWK: Effective AWK Programming +@end ifclear @set SUBTITLE A User's Guide for GNU Awk @set EDITION 4.1 @@ -423,8 +426,9 @@ particular records in a file and perform operations upon them. @end ifnottex @menu -* Foreword:: Some nice words about this +* Foreword3:: Some nice words about this @value{DOCUMENT}. +* Foreword4:: More nice words. * Preface:: What this @value{DOCUMENT} is about; brief history and acknowledgments. * Getting Started:: A basic introduction to using @@ -555,8 +559,8 @@ particular records in a file and perform operations upon them. * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting @code{FS} from the - command line. +* Command Line Field Separator:: Setting @code{FS} from the command + line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -600,10 +604,12 @@ particular records in a file and perform operations upon them. * Printf Examples:: Several examples. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in @command{gawk}. @command{gawk} allows access to inherited file descriptors. -* Special FD:: Special files for I/O. +* Other Inherited Files:: Accessing other open files with + @command{gawk}. * Special Network:: Special files for network communications. * Special Caveats:: Things to watch out for. @@ -696,7 +702,7 @@ particular records in a file and perform operations upon them. record. * Nextfile Statement:: Stop processing the current file. * Exit Statement:: Stop execution of @command{awk}. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * User-modified:: Built-in variables that you change to control @command{awk}. * Auto-set:: Built-in variables where @command{awk} @@ -716,12 +722,12 @@ particular records in a file and perform operations upon them. elements. * Controlling Scanning:: Controlling the order in which arrays are scanned. -* Delete:: The @code{delete} statement removes an - element from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in @command{awk}. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The @code{delete} statement removes an + element from an array. * Multidimensional:: Emulating multidimensional arrays in @command{awk}. * Multiscanning:: Scanning multidimensional arrays. @@ -780,6 +786,8 @@ particular records in a file and perform operations upon them. * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the + shell. * Data File Management:: Functions for managing command-line data files. * Filetrans Function:: A function for handling data file @@ -894,7 +902,6 @@ particular records in a file and perform operations upon them. * Extension API Description:: A full description of the API. * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with @@ -907,6 +914,7 @@ particular records in a file and perform operations upon them. * Two-way processors:: Registering a two-way processor. * Printing Messages:: Functions for printing messages. * Updating @code{ERRNO}:: Functions for updating @code{ERRNO}. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -945,9 +953,9 @@ particular records in a file and perform operations upon them. processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to @code{gettimeofday()} and @code{sleep()}. +* Extension Sample API Tests:: Tests for the API. * gawkextlib:: The @code{gawkextlib} project. * Extension summary:: Extension summary. * Extension Exercises:: Exercises. @@ -976,6 +984,7 @@ particular records in a file and perform operations upon them. * Unix Installation:: Installing @command{gawk} under various versions of Unix. * Quick Installation:: Compiling @command{gawk} under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. * Non-Unix Installation:: Installation on Other Operating @@ -1048,8 +1057,8 @@ for enrichening our lives in innumerable ways. @summarycontents @contents -@node Foreword -@unnumbered Foreword +@node Foreword3 +@unnumbered Foreword to the Third Edition @c This bit is post-processed by a script which turns the chapter @c tag into a preface tag, and moves this stuff to before the title. @@ -1083,7 +1092,7 @@ books on Unix, I found the gray AWK book, a.k.a.@: Aho, Kernighan and Weinberger, @cite{The AWK Programming Language}, Addison-Wesley, 1988. AWK's simple programming paradigm---find a pattern in the input and then perform an action---often reduced complex or tedious -data manipulations to few lines of code. I was excited to try my +data manipulations to a few lines of code. I was excited to try my hand at programming in AWK. Alas, the @command{awk} on my computer was a limited version of the @@ -1199,6 +1208,58 @@ March, 2001 @end display @end ifnotdocbook +@node Foreword4 +@unnumbered Foreword to the Fourth Edition + +@c This bit is post-processed by a script which turns the chapter +@c tag into a preface tag, and moves this stuff to before the title. +@c Bleah. +@docbook + <prefaceinfo> + <author> + <firstname>Michael</firstname> + <surname>Brennan</surname> + <!-- can't put mawk into command tags. sigh. --> + <affiliation><jobtitle>Author of mawk</jobtitle></affiliation> + </author> + <date>October, 2014</date> + </prefaceinfo> +@end docbook + +Some things don't change. Thirteen years ago I wrote: +``If you use AWK or want to learn how, then read this book.'' +True then and still true today. + +Learning to use a programming language is more than mastering the +syntax. One needs to acquire an understanding of how to use the +features of the language to solve practical programming problems. +A focus of this book is many examples that show how to use AWK. + +Some things do change. Our computers are much faster and have more memory. +Consequently, speed and storage inefficiencies of a high level language +matter less. Prototyping in AWK and then rewriting in C for performance +reasons happens less, because more often the prototype is fast enough. + +Of course, there are computing operations that are best done in C or C++. +With @command{gawk} 4.1 and later, you do not have to choose between writing +your program in AWK or in C/C++. You can write most of your +program in AWK and the aspects that require C/C++ capabilities can be written +in C/C++ and then the pieces glued together when the @command{gawk} module loads +the C/C++ module as a dynamic plug-in. +@c Chapter 16 +@ref{Dynamic Extensions}, +has all the +details, and as expected, many examples to help you learn the ins and outs. + +@ifnotdocbook +@cindex Brennan, Michael +@display +Michael Brennan +Author of @command{mawk} +October, 2014 +@end display +@end ifnotdocbook + @node Preface @unnumbered Preface @c I saw a comment somewhere that the preface should describe the book itself, @@ -1217,7 +1278,7 @@ March, 2001 <affiliation><jobtitle>Nof Ayalon</jobtitle></affiliation> <affiliation><jobtitle>ISRAEL</jobtitle></affiliation> </author> - <date>June, 2014</date> + <date>December, 2014</date> </prefaceinfo> @end docbook @@ -1230,8 +1291,7 @@ language that makes it easy to handle simple data-reformatting jobs. The GNU implementation of @command{awk} is called @command{gawk}; if you invoke it with the proper options or environment variables -(@pxref{Options}), it is fully -compatible with +it is fully compatible with the POSIX@footnote{The 2008 POSIX standard is accessible online at @w{@url{http://www.opengroup.org/onlinepubs/9699919799/}.}} specification of the @command{awk} language @@ -1239,7 +1299,7 @@ and with the Unix version of @command{awk} maintained by Brian Kernighan. This means that all properly written @command{awk} programs should work with @command{gawk}. -Thus, we usually don't distinguish between @command{gawk} and other +So most of the time, we don't distinguish between @command{gawk} and other @command{awk} implementations. @cindex @command{awk}, POSIX and, See Also POSIX @command{awk} @@ -1248,7 +1308,7 @@ Thus, we usually don't distinguish between @command{gawk} and other @cindex @command{gawk}, @command{awk} and @cindex @command{awk}, @command{gawk} and @cindex @command{awk}, uses for -Using @command{awk} allows you to: +Using @command{awk} you can: @itemize @value{BULLET} @item @@ -1286,15 +1346,15 @@ Sort data Perform simple network communications @item -Profile and debug @command{awk} programs. +Profile and debug @command{awk} programs @item -Extend the language with functions written in C or C++. +Extend the language with functions written in C or C++ @end itemize This @value{DOCUMENT} teaches you about the @command{awk} language and how you can use it effectively. You should already be familiar with basic -system commands, such as @command{cat} and @command{ls},@footnote{These commands +system commands, such as @command{cat} and @command{ls},@footnote{These utilities are available on POSIX-compliant systems, as well as on traditional Unix-based systems. If you are using some other operating system, you still need to be familiar with the ideas of I/O redirection and pipes.} as well as basic shell @@ -1316,10 +1376,9 @@ Microsoft Windows @ifclear FOR_PRINT (all versions) and OS/2 PCs, @end ifclear -and OpenVMS. -(Some other, obsolete systems to which @command{gawk} was once ported -are no longer supported and the code for those systems -has been removed.) +and OpenVMS.@footnote{Some other, obsolete systems to which @command{gawk} +was once ported are no longer supported and the code for those systems +has been removed.} @menu * History:: The history of @command{gawk} and @@ -1368,13 +1427,13 @@ The version in System V Release 4 (1989) added some new features and cleaned up the behavior in some of the ``dark corners'' of the language. The specification for @command{awk} in the POSIX Command Language and Utilities standard further clarified the language. -Both the @command{gawk} designers and the original Bell Laboratories @command{awk} -designers provided feedback for the POSIX specification. +Both the @command{gawk} designers and the original @command{awk} designers at Bell Laboratories +provided feedback for the POSIX specification. @cindex Rubin, Paul @cindex Fenlason, Jay @cindex Trueman, David -Paul Rubin wrote the GNU implementation, @command{gawk}, in 1986. +Paul Rubin wrote @command{gawk} in 1986. Jay Fenlason completed it, with advice from Richard Stallman. John Woods contributed parts of the code as well. In 1988 and 1989, David Trueman, with help from me, thoroughly reworked @command{gawk} for compatibility @@ -1397,7 +1456,7 @@ an @command{awk}-level debugger. This version became available as @command{gawk} @value{PVERSION} 4.0, in 2011. @xref{Contributors}, -for a complete list of those who made important contributions to @command{gawk}. +for a full list of those who made important contributions to @command{gawk}. @node Names @unnumberedsec A Rose by Any Other Name @@ -1463,8 +1522,8 @@ entry ``differences in @command{awk} and @command{gawk}.''} @ifset FOR_PRINT implementations. @end ifset -Finally, any @command{gawk} features that are not in -the POSIX standard for @command{awk} are noted. +Finally, it notes any @command{gawk} features that are not in +the POSIX standard for @command{awk}. @ifnotinfo This @value{DOCUMENT} has the difficult task of being both a tutorial and a reference. @@ -1483,7 +1542,7 @@ All appear in the index, under the heading ``sidebar.'' Most of the time, the examples use complete @command{awk} programs. Some of the more advanced sections show only the part of the @command{awk} -program that illustrates the concept currently being described. +program that illustrates the concept being described. While this @value{DOCUMENT} is aimed principally at people who have not been exposed @@ -1531,7 +1590,7 @@ for getting most things done in a program. @ref{Patterns and Actions}, describes how to write patterns for matching records, actions for -doing something when a record is matched, and the built-in variables +doing something when a record is matched, and the predefined variables @command{awk} and @command{gawk} use. @ref{Arrays}, @@ -1541,9 +1600,9 @@ sorting arrays in @command{gawk}. It also describes how @command{gawk} provides arrays of arrays. @ref{Functions}, -describes the built-in functions @command{awk} and -@command{gawk} provide, as well as how to define -your own functions. +describes the built-in functions @command{awk} and @command{gawk} provide, +as well as how to define your own functions. It also discusses how +@command{gawk} lets you call functions indirectly. Part II shows how to use @command{awk} and @command{gawk} for problem solving. There is lots of code here for you to read and learn from. @@ -1562,21 +1621,21 @@ Part III focuses on features specific to @command{gawk}. It contains the following chapters: @ref{Advanced Features}, -describes a number of @command{gawk}-specific advanced features. +describes a number of advanced features. Of particular note -are the abilities to have two-way communications with another process, +are the abilities to control the order of array traversal, +have two-way communications with another process, perform TCP/IP networking, and profile your @command{awk} programs. @ref{Internationalization}, -describes special features in @command{gawk} for translating program +describes special features for translating program messages into different languages at runtime. -@ref{Debugger}, describes the @command{awk} debugger. +@ref{Debugger}, describes the @command{gawk} debugger. @ref{Arbitrary Precision Arithmetic}, -describes advanced arithmetic facilities provided by -@command{gawk}. +describes advanced arithmetic facilities. @ref{Dynamic Extensions}, describes how to add new variables and functions to @command{gawk} by writing extensions in C or C++. @@ -1616,9 +1675,10 @@ printed edition. You may find them online, as follows: @uref{http://www.gnu.org/software/gawk/manual/html_node/Notes.html, The appendix on implementation notes} -describes how to disable @command{gawk}'s extensions, as -well as how to contribute new code to @command{gawk}, -and some possible future directions for @command{gawk} development. +describes how to disable @command{gawk}'s extensions, how to contribute +new code to @command{gawk}, where to find information on some possible +future directions for @command{gawk} development, and the design decisions +behind the extension API. @uref{http://www.gnu.org/software/gawk/manual/html_node/Basic-Concepts.html, The appendix on basic concepts} @@ -1636,7 +1696,7 @@ The GNU FDL} is the license that covers this @value{DOCUMENT}. Some of the chapters have exercise sections; these have also been -omitted from the print edition. +omitted from the print edition but are available online. @end ifset @ifclear FOR_PRINT @@ -1758,8 +1818,8 @@ the picture of a flashlight in the margin, as shown here. They also appear in the index under the heading ``dark corner.'' @end ifclear -As noted by the opening quote, though, any coverage of dark corners is, -by definition, incomplete. +But, as noted by the opening quote, any coverage of dark +corners is by definition incomplete. @cindex c.e., See common extensions Extensions to the standard @command{awk} language that are supported by @@ -1833,9 +1893,7 @@ available for download from the Internet. @ifnotinfo The @value{DOCUMENT} you are reading is actually free---at least, the information in it is free to anyone. The machine-readable -source code for the @value{DOCUMENT} comes with @command{gawk}; anyone -may take this @value{DOCUMENT} to a copying machine and make as many -copies as they like. +source code for the @value{DOCUMENT} comes with @command{gawk}. @ifclear FOR_PRINT (Take a moment to check the Free Documentation License in @ref{GNU Free Documentation License}.) @@ -1843,7 +1901,7 @@ License in @ref{GNU Free Documentation License}.) @end ifnotinfo @cindex Close, Diane -The @value{DOCUMENT} itself has gone through a number of previous editions. +The @value{DOCUMENT} itself has gone through multiple previous editions. Paul Rubin wrote the very first draft of @cite{The GAWK Manual}; it was around 40 pages in size. Diane Close and Richard Stallman improved it, yielding a @@ -1859,15 +1917,14 @@ The FSF published the first two editions under the title @cite{The GNU Awk User's Guide}. @ifset FOR_PRINT SSC published two editions of the @value{DOCUMENT} under the -title @cite{Effective awk Programming}, and in O'Reilly published +title @cite{Effective awk Programming}, and O'Reilly published the third edition in 2001. @end ifset This edition maintains the basic structure of the previous editions. -For FSF edition 4.0, the content has been thoroughly reviewed -and updated. All references to @command{gawk} versions prior to 4.0 have been -removed. -Of significant note for this edition was @ref{Debugger}. +For FSF edition 4.0, the content was thoroughly reviewed and updated. All +references to @command{gawk} versions prior to 4.0 were removed. +Of significant note for that edition was @ref{Debugger}. For FSF edition @ifclear FOR_PRINT @@ -1881,8 +1938,7 @@ the content has been reorganized into parts, and the major new additions are @ref{Arbitrary Precision Arithmetic}, and @ref{Dynamic Extensions}. -This @value{DOCUMENT} will undoubtedly continue to evolve. An electronic -version comes with the @command{gawk} distribution from the FSF. If you +This @value{DOCUMENT} will undoubtedly continue to evolve. If you find an error in this @value{DOCUMENT}, please report it! @xref{Bugs}, for information on submitting problem reports electronically. @@ -1891,7 +1947,7 @@ for information on submitting problem reports electronically. @unnumberedsec How to Stay Current It may be you have a version of @command{gawk} which is newer than the -one described in this @value{DOCUMENT}. To find out what has changed, +one described here. To find out what has changed, you should first look at the @file{NEWS} file in the @command{gawk} distribution, which provides a high level summary of what changed in each release. @@ -1926,8 +1982,10 @@ a @command{gawk} extension that you would like to share with the rest of the world, please see @uref{http://awk.info/?contribute} for how to contribute it to the web site. +@ignore As of this writing, this website is in search of a maintainer; please contact me if you are interested. +@end ignore @ignore Other links: @@ -2063,15 +2121,24 @@ Andrew Schorr, Corinna Vinschen, and Eli Zaretskii (in alphabetical order) -make up the current -@command{gawk} ``crack portability team.'' Without their hard work and -help, @command{gawk} would not be nearly the fine program it is today. It -has been and continues to be a pleasure working with this team of fine -people. +make up the current @command{gawk} ``crack portability team.'' Without +their hard work and help, @command{gawk} would not be nearly the robust, +portable program it is today. It has been and continues to be a pleasure +working with this team of fine people. Notable code and documentation contributions were made by a number of people. @xref{Contributors}, for the full list. +@ifset FOR_PRINT +@cindex Oram, Andy +Thanks to Andy Oram, of O'Reilly Media, for initiating +the fourth edition and for his support during the work. +@end ifset + +Thanks to Michael Brennan for the Foreword. + +@cindex Duman, Patrice +@cindex Berry, Karl Thanks to Patrice Dumas for the new @command{makeinfo} program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. @@ -2113,7 +2180,7 @@ take advantage of those opportunities. Arnold Robbins @* Nof Ayalon @* ISRAEL @* -May, 2014 +December, 2014 @end iftex @ifnotinfo @@ -2332,7 +2399,7 @@ to keep you from worrying about the complexities of computer programming: @example -$ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} +$ @kbd{awk 'BEGIN @{ print "Don\47t Panic!" @}'} @print{} Don't Panic! @end example @@ -2340,11 +2407,11 @@ $ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} reading any input. If there are no other statements in your program, as is the case here, @command{awk} just stops, instead of trying to read input it doesn't know how to process. -The @samp{\47} is a magic way of getting a single quote into +The @samp{\47} is a magic way (explained later) of getting a single quote into the program, without having to engage in ugly shell quoting tricks. @quotation NOTE -As a side note, if you use Bash as your shell, you should execute the +If you use Bash as your shell, you should execute the command @samp{set +H} before running this program interactively, to disable the C shell-style command history, which treats @samp{!} as a special character. We recommend putting this command into your personal @@ -2374,7 +2441,7 @@ $ @kbd{awk '@{ print @}'} @cindex @command{awk} programs, running @cindex @command{awk} programs, lengthy @cindex files, @command{awk} programs in -Sometimes your @command{awk} programs can be very long. In this case, it is +Sometimes @command{awk} programs are very long. In these cases, it is more convenient to put the program into a separate file. In order to tell @command{awk} to use that file for its program, you type: @@ -2404,7 +2471,7 @@ awk -f advice does the same thing as this one: @example -awk "BEGIN @{ print \"Don't Panic!\" @}" +awk 'BEGIN @{ print "Don\47t Panic!" @}' @end example @cindex quoting in @command{gawk} command lines @@ -2416,6 +2483,8 @@ specify with @option{-f}, because most @value{FN}s don't contain any of the shel special characters. Notice that in @file{advice}, the @command{awk} program did not have single quotes around it. The quotes are only needed for programs that are provided on the @command{awk} command line. +(Also, placing the program in a file allows us to use a literal single quote in the program +text, instead of the magic @samp{\47}.) @c STARTOFRANGE sq1x @cindex single quote (@code{'}) in @command{gawk} command lines @@ -2474,7 +2543,7 @@ written in @command{awk}. according to the instructions in your program. (This is different from a @dfn{compiled} language such as C, where your program is first compiled into machine code that is executed directly by your system's -hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +processor.) The @command{awk} utility is thus termed an @dfn{interpreter}. Many modern languages are interperted. The line beginning with @samp{#!} lists the full @value{FN} of an @@ -2483,9 +2552,9 @@ to pass to that interpreter. The operating system then runs the interpreter with the given argument and the full argument list of the executed program. The first argument in the list is the full @value{FN} of the @command{awk} program. The rest of the argument list contains -either options to @command{awk}, or @value{DF}s, or both. Note that on +either options to @command{awk}, or @value{DF}s, or both. (Note that on many systems @command{awk} may be found in @file{/usr/bin} instead of -in @file{/bin}. Caveat Emptor. +in @file{/bin}.) Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2663,8 +2732,14 @@ Thus, the example seen @ifnotinfo previously @end ifnotinfo -in @ref{Read Terminal}, -is applicable: +in @ref{Read Terminal}: + +@example +awk 'BEGIN @{ print "Don\47t Panic!" @}' +@end example + +@noindent +could instead be written this way: @example $ @kbd{awk "BEGIN @{ print \"Don't Panic!\" @}"} @@ -2694,7 +2769,7 @@ awk -F"" '@var{program}' @var{files} # wrong! @end example @noindent -In the second case, @command{awk} will attempt to use the text of the program +In the second case, @command{awk} attempts to use the text of the program as the value of @code{FS}, and the first @value{FN} as the text of the program! This results in syntax errors at best, and confusing behavior at worst. @end itemize @@ -2759,6 +2834,9 @@ $ awk -v sq="'" 'BEGIN @{ print "Here is a single quote <" sq ">" @}' @print{} Here is a single quote <'> @end example +(Here, the two string constants and the value of @code{sq} are concatenated +into a single string which is printed by @code{print}.) + If you really need both single and double quotes in your @command{awk} program, it is probably best to move it into a separate file, where the shell won't be part of the picture, and you can say what you mean. @@ -2822,7 +2900,7 @@ The second @value{DF}, called @file{inventory-shipped}, contains information about monthly shipments. In both files, each line is considered to be one @dfn{record}. -In the @value{DF} @file{mail-list}, each record contains the name of a person, +In @file{mail-list}, each record contains the name of a person, his/her phone number, his/her email-address, and a code for their relationship with the author of the list. The columns are aligned using spaces. @@ -2982,7 +3060,7 @@ Print the length of the longest line in @file{data}: @example expand data | awk '@{ if (x < length($0)) x = length($0) @} - END @{ print "maximum line length is " x @}' + END @{ print "maximum line length is " x @}' @end example This example differs slightly from the previous one: @@ -3014,7 +3092,7 @@ Print the total number of bytes used by @var{files}: @example ls -l @var{files} | awk '@{ x += $5 @} - END @{ print "total bytes: " x @}' + END @{ print "total bytes: " x @}' @end example @item @@ -3058,7 +3136,7 @@ the program would print the odd-numbered lines. @cindex @command{awk} programs The @command{awk} utility reads the input files one line at a -time. For each line, @command{awk} tries the patterns of each of the rules. +time. For each line, @command{awk} tries the patterns of each rule. If several patterns match, then several actions execute in the order in which they appear in the @command{awk} program. If no patterns match, then no actions run. @@ -3066,7 +3144,7 @@ no actions run. After processing all the rules that match the line (and perhaps there are none), @command{awk} reads the next line. (However, @pxref{Next Statement}, -and also @pxref{Nextfile Statement}). +and also @pxref{Nextfile Statement}.) This continues until the program reaches the end of the file. For example, the following @command{awk} program contains two rules: @@ -3140,13 +3218,12 @@ the file was last modified. Its output looks like this: @noindent @cindex line continuations, with C shell The first field contains read-write permissions, the second field contains -the number of links to the file, and the third field identifies the owner of -the file. The fourth field identifies the group of the file. -The fifth field contains the size of the file in bytes. The +the number of links to the file, and the third field identifies the file's owner. +The fourth field identifies the file's group. +The fifth field contains the file's size in bytes. The sixth, seventh, and eighth fields contain the month, day, and time, respectively, that the file was last modified. Finally, the ninth field -contains the @value{FN}.@footnote{The @samp{LC_ALL=C} is -needed to produce this traditional-style output from @command{ls}.} +contains the @value{FN}. @c @cindex automatic initialization @cindex initialization, automatic @@ -3550,13 +3627,13 @@ The @option{-v} option can only set one variable, but it can be used more than once, setting another variable each time, like this: @samp{awk @w{-v foo=1} @w{-v bar=2} @dots{}}. -@cindex built-in variables, @code{-v} option@comma{} setting with -@cindex variables, built-in, @code{-v} option@comma{} setting with +@cindex predefined variables, @code{-v} option@comma{} setting with +@cindex variables, predefined @code{-v} option@comma{} setting with @quotation CAUTION Using @option{-v} to set the values of the built-in variables may lead to surprising results. @command{awk} will reset the values of those variables as it needs to, possibly ignoring any -predefined value you may have given. +initial value you may have given. @end quotation @item -W @var{gawk-opt} @@ -3639,7 +3716,7 @@ Print the short version of the General Public License and then exit. @cindex variables, global, printing list of Print a sorted list of global variables, their types, and final values to @var{file}. If no @var{file} is provided, print this -list to the file named @file{awkvars.out} in the current directory. +list to a file named @file{awkvars.out} in the current directory. No space is allowed between the @option{-d} and @var{file}, if @var{file} is supplied. @@ -3659,7 +3736,8 @@ names like @code{i}, @code{j}, etc.) @cindex @command{awk} debugging, enabling Enable debugging of @command{awk} programs (@pxref{Debugging}). -By default, the debugger reads commands interactively from the keyboard. +By default, the debugger reads commands interactively from the keyboard +(standard input). The optional @var{file} argument allows you to specify a file with a list of commands for the debugger to execute non-interactively. No space is allowed between the @option{-D} and @var{file}, if @@ -3735,7 +3813,7 @@ that @command{gawk} accepts and then exit. @cindex @option{-i} option @cindex @option{--include} option @cindex @command{awk} programs, location of -Read @command{awk} source library from @var{source-file}. This option +Read an @command{awk} source library from @var{source-file}. This option is completely equivalent to using the @code{@@include} directive inside your program. This option is very similar to the @option{-f} option, but there are two important differences. First, when @option{-i} is @@ -3759,7 +3837,7 @@ environment variable. The correct library suffix for your platform will be supplied by default, so it need not be specified in the extension name. The extension initialization routine should be named @code{dl_load()}. An alternative is to use the @code{@@load} keyword inside the program to load -a shared library. This feature is described in detail in @ref{Dynamic Extensions}. +a shared library. This advanced feature is described in detail in @ref{Dynamic Extensions}. @item @option{-L}[@var{value}] @itemx @option{--lint}[@code{=}@var{value}] @@ -3808,6 +3886,8 @@ values in input data @quotation CAUTION This option can severely break old programs. Use with care. + +This option may disappear in a future version of @command{gawk}. @end quotation @item @option{-N} @@ -3971,6 +4051,7 @@ if they had been concatenated together into one big file. This is useful for creating libraries of @command{awk} functions. These functions can be written once and then retrieved from a standard place, instead of having to be included into each individual program. +The @option{-i} option is similar in this regard. (As mentioned in @ref{Definition Syntax}, function names must be unique.) @@ -4044,15 +4125,18 @@ Any additional arguments on the command line are normally treated as input files to be processed in the order specified. However, an argument that has the form @code{@var{var}=@var{value}}, assigns the value @var{value} to the variable @var{var}---it does not specify a -file at all. -(See -@ref{Assignment Options}.) +file at all. (See @ref{Assignment Options}.) In the following example, +@var{count=1} is a variable assignment, not a @value{FN}: + +@example +awk -f program.awk file1 count=1 file2 +@end example @cindex @command{gawk}, @code{ARGIND} variable in @cindex @code{ARGIND} variable, command-line arguments @cindex @code{ARGV} array, indexing into @cindex @code{ARGC}/@code{ARGV} variables, command-line arguments -All these arguments are made available to your @command{awk} program in the +All the command-line arguments are made available to your @command{awk} program in the @code{ARGV} array (@pxref{Built-in Variables}). Command-line options and the program text (if present) are omitted from @code{ARGV}. All other arguments, including variable assignments, are @@ -4162,72 +4246,80 @@ behaves. @cindex @env{AWKPATH} environment variable @cindex directories, searching for source files @cindex search paths, for source files -@cindex differences in @command{awk} and @command{gawk}, @code{AWKPATH} environment variable +@cindex differences in @command{awk} and @command{gawk}, @env{AWKPATH} environment variable @ifinfo The previous @value{SECTION} described how @command{awk} program files can be named on the command line with the @option{-f} option. @end ifinfo In most @command{awk} -implementations, you must supply a precise path name for each program +implementations, you must supply a precise pathname for each program file, unless the file is in the current directory. -But in @command{gawk}, if the @value{FN} supplied to the @option{-f} +But with @command{gawk}, if the @value{FN} supplied to the @option{-f} or @option{-i} options does not contain a directory separator @samp{/}, then @command{gawk} searches a list of directories (called the @dfn{search path}), one by one, looking for a file with the specified name. The search path is a string consisting of directory names -separated by colons@footnote{Semicolons on MS-Windows and MS-DOS.}. @command{gawk} gets its search path from the +separated by colons.@footnote{Semicolons on MS-Windows and MS-DOS.} +@command{gawk} gets its search path from the @env{AWKPATH} environment variable. If that variable does not exist, -@command{gawk} uses a default path, -@samp{.:/usr/local/share/awk}.@footnote{Your version of @command{gawk} -may use a different directory; it -will depend upon how @command{gawk} was built and installed. The actual -directory is the value of @samp{$(datadir)} generated when -@command{gawk} was configured. You probably don't need to worry about this, -though.} +or if it has an empty value, +@command{gawk} uses a default path (described shortly). The search path feature is particularly helpful for building libraries of useful @command{awk} functions. The library files can be placed in a standard directory in the default path and then specified on -the command line with a short @value{FN}. Otherwise, the full @value{FN} -would have to be typed for each file. +the command line with a short @value{FN}. Otherwise, you would have to +type the full @value{FN} for each file. -By using the @option{-i} option, or the @option{-e} and @option{-f} options, your command-line +By using the @option{-i} or @option{-f} options, your command-line @command{awk} programs can use facilities in @command{awk} library files (@pxref{Library Functions}). Path searching is not done if @command{gawk} is in compatibility mode. This is true for both @option{--traditional} and @option{--posix}. @xref{Options}. -If the source code is not found after the initial search, the path is searched -again after adding the default @samp{.awk} suffix to the @value{FN}. +If the source code file is not found after the initial search, the path is searched +again after adding the suffix @samp{.awk} to the @value{FN}. -@quotation NOTE -@c 4/2014: -@c using @samp{.} to get quotes, since @file{} no longer supplies them. -To include -the current directory in the path, either place -@samp{.} explicitly in the path or write a null entry in the -path. (A null entry is indicated by starting or ending the path with a -colon or by placing two colons next to each other [@samp{::}].) -This path search mechanism is similar +@command{gawk}'s path search mechanism is similar to the shell's. (See @uref{http://www.gnu.org/software/bash/manual/, -@cite{The Bourne-Again SHell manual}.}) +@cite{The Bourne-Again SHell manual}}.) +It treats a null entry in the path as indicating the current +directory. +(A null entry is indicated by starting or ending the path with a +colon or by placing two colons next to each other [@samp{::}].) -However, @command{gawk} always looks in the current directory @emph{before} -searching @env{AWKPATH}, so there is no real reason to include -the current directory in the search path. -@c Prior to 4.0, gawk searched the current directory after the -@c path search, but it's not worth documenting it. +@quotation NOTE +To include the current directory in the path, either place @file{.} +as an entry in the path or write a null entry in the path. + +Different past versions of @command{gawk} would also look explicitly in +the current directory, either before or after the path search. As of +@value{PVERSION} 4.1.2, this no longer happens, and if you wish to look +in the current directory, you must include @file{.} either as a separate +entry, or as a null entry in the search path. @end quotation -If @env{AWKPATH} is not defined in the -environment, @command{gawk} places its default search path into -@code{ENVIRON["AWKPATH"]}. This makes it easy to determine -the actual search path that @command{gawk} used -from within an @command{awk} program. +The default value for @env{AWKPATH} is +@samp{.:/usr/local/share/awk}.@footnote{Your version of @command{gawk} +may use a different directory; it +will depend upon how @command{gawk} was built and installed. The actual +directory is the value of @code{$(datadir)} generated when +@command{gawk} was configured. You probably don't need to worry about this, +though.} Since @file{.} is included at the beginning, @command{gawk} +searches first in the current directory and then in @file{/usr/local/share/awk}. +In practice, this means that you will rarely need to change the +value of @env{AWKPATH}. + +@xref{Shell Startup Files}, for information on functions that help to +manipulate the @env{AWKPATH} variable. + +@command{gawk} places the value of the search path that it used into +@code{ENVIRON["AWKPATH"]}. This provides access to the actual search +path value from within an @command{awk} program. While you can change @code{ENVIRON["AWKPATH"]} within your @command{awk} program, this has no effect on the running program's behavior. This makes @@ -4251,6 +4343,18 @@ the platform. For example, on GNU/Linux systems, the suffix @samp{.so} is used. The search path specified is also used for extensions loaded via the @code{@@load} keyword (@pxref{Loading Shared Libraries}). +If @env{AWKLIBPATH} does not exist in the environment, or if it has +an empty value, @command{gawk} uses a default path; this +is typically @samp{/usr/local/lib/gawk}, although it can vary depending +upon how @command{gawk} was built. + +@xref{Shell Startup Files}, for information on functions that help to +manipulate the @env{AWKLIBPATH} variable. + +@command{gawk} places the value of the search path that it used into +@code{ENVIRON["AWKLIBPATH"]}. This provides access to the actual search +path value from within an @command{awk} program. + @node Other Environment Variables @subsection Other Environment Variables @@ -4259,16 +4363,6 @@ behavior, but they are more specialized. Those in the following list are meant to be used by regular users. @table @env -@item POSIXLY_CORRECT -Causes @command{gawk} to switch to POSIX compatibility -mode, disabling all traditional and GNU extensions. -@xref{Options}. - -@item GAWK_SOCK_RETRIES -Controls the number of times @command{gawk} attempts to -retry a two-way TCP/IP (socket) connection before giving up. -@xref{TCP/IP Networking}. - @item GAWK_MSEC_SLEEP Specifies the interval between connection retries, in milliseconds. On systems that do not support @@ -4279,6 +4373,16 @@ the value is rounded up to an integral number of seconds. Specifies the time, in milliseconds, for @command{gawk} to wait for input before returning with an error. @xref{Read Timeout}. + +@item GAWK_SOCK_RETRIES +Controls the number of times @command{gawk} attempts to +retry a two-way TCP/IP (socket) connection before giving up. +@xref{TCP/IP Networking}. + +@item POSIXLY_CORRECT +Causes @command{gawk} to switch to POSIX compatibility +mode, disabling all traditional and GNU extensions. +@xref{Options}. @end table The environment variables in the following list are meant @@ -4293,7 +4397,7 @@ file as the size of the memory buffer to allocate for I/O. Otherwise, the value should be a number, and @command{gawk} uses that number as the size of the buffer to allocate. (When this variable is not set, @command{gawk} uses the smaller of the file's size and the ``default'' -blocksize, which is usually the filesystems I/O blocksize.) +blocksize, which is usually the filesystem's I/O blocksize.) @item AWK_HASH If this variable exists with a value of @samp{gst}, @command{gawk} @@ -4308,10 +4412,11 @@ for debugging problems on filesystems on non-POSIX operating systems where I/O is performed in records, not in blocks. @item GAWK_MSG_SRC -If this variable exists, @command{gawk} includes the source file -name and line number from which warning and/or fatal messages +If this variable exists, @command{gawk} includes the file +name and line number within the @command{gawk} source code +from which warning and/or fatal messages are generated. Its purpose is to help isolate the source of a -message, since there can be multiple places which produce the +message, since there are multiple places which produce the same warning or error message. @item GAWK_NO_DFA @@ -4327,11 +4432,11 @@ This specifies the amount by which @command{gawk} should grow its internal evaluation stack, when needed. @item INT_CHAIN_MAX -The average number of items @command{gawk} will maintain on a +The intended maximum number of items @command{gawk} will maintain on a hash chain for managing arrays indexed by integers. @item STR_CHAIN_MAX -The average number of items @command{gawk} will maintain on a +The intended maximum number of items @command{gawk} will maintain on a hash chain for managing arrays indexed by strings. @item TIDYMEM @@ -4404,8 +4509,8 @@ produces the following result: @example $ @kbd{gawk -f test2} -@print{} This is file test1. -@print{} This is file test2. +@print{} This is script test1. +@print{} This is script test2. @end example @code{gawk} runs the @file{test2} script which includes @file{test1} @@ -4435,9 +4540,9 @@ following results: @example $ @kbd{gawk -f test3} -@print{} This is file test1. -@print{} This is file test2. -@print{} This is file test3. +@print{} This is script test1. +@print{} This is script test2. +@print{} This is script test3. @end example The @value{FN} can, of course, be a pathname. For example: @@ -4454,9 +4559,9 @@ or: @end example @noindent -are valid. The @code{AWKPATH} environment variable can be of great +are valid. The @env{AWKPATH} environment variable can be of great value when using @code{@@include}. The same rules for the use -of the @code{AWKPATH} variable in command-line file searches +of the @env{AWKPATH} variable in command-line file searches (@pxref{AWKPATH Variable}) apply to @code{@@include} also. @@ -4464,7 +4569,7 @@ This is very helpful in constructing @command{gawk} function libraries. If you have a large script with useful, general purpose @command{awk} functions, you can break it down into library files and put those files in a special directory. You can then include those ``libraries,'' using -either the full pathnames of the files, or by setting the @code{AWKPATH} +either the full pathnames of the files, or by setting the @env{AWKPATH} environment variable accordingly and then using @code{@@include} with just the file part of the full pathname. Of course you can have more than one directory to keep library files; the more complex the working @@ -4524,6 +4629,7 @@ that requires access to an extension. @ref{Dynamic Extensions}, describes how to write extensions (in C or C++) that can be loaded with either @code{@@load} or the @option{-l} option. +It also describes the @code{ordchr} extension. @node Obsolete @section Obsolete Options and/or Features @@ -4592,15 +4698,15 @@ awk '@{ sum += $1 @} END @{ print sum @}' @end example @command{gawk} actually supports this but it is purposely undocumented -because it is considered bad style. The correct way to write such a program -is either +because it is bad style. The correct way to write such a program +is either: @example awk '@{ sum += $1 @} ; END @{ print sum @}' @end example @noindent -or +or: @example awk '@{ sum += $1 @} @@ -4608,8 +4714,7 @@ awk '@{ sum += $1 @} @end example @noindent -@xref{Statements/Lines}, for a fuller -explanation. +@xref{Statements/Lines}, for a fuller explanation. You can insert newlines after the @samp{;} in @code{for} loops. This seems to have been a long-undocumented feature in Unix @command{awk}. @@ -4649,7 +4754,8 @@ affects how @command{awk} processes input. @item You can use a single minus sign (@samp{-}) to refer to standard input -on the command line. +on the command line. @command{gawk} also lets you use the special +@value{FN} @file{/dev/stdin}. @item @command{gawk} pays attention to a number of environment variables. @@ -4838,7 +4944,7 @@ such as TAB or newline. While there is nothing to stop you from entering most unprintable characters directly in a string constant or regexp constant, they may look ugly. -The following table lists +The following list presents all the escape sequences used in @command{awk} and what they represent. Unless noted otherwise, all these escape sequences apply to both string constants and regexp constants: @@ -4904,6 +5010,7 @@ of hexadecimal digits (@samp{0}--@samp{9}, and either @samp{A}--@samp{F} or @samp{a}--@samp{f}). A maximum of two digts are allowed after the @samp{\x}. Any further hexadecimal digits are treated as simple letters or numbers. @value{COMMONEXT} +(The @samp{\x} escape sequence is not allowed in POSIX awk.) @quotation CAUTION In ISO C, the escape sequence continues until the first nonhexadecimal @@ -4912,7 +5019,10 @@ digit is seen. For many years, @command{gawk} would continue incorporating hexadecimal digits into the value until a non-hexadecimal digit or the end of the string was encountered. -However, using more than two hexadecimal digits produces +However, using more than two hexadecimal digits produced +undefined results. +As of @value{PVERSION} @strong{FIXME:} 4.3.0, only two digits +are processed. @end quotation @cindex @code{\} (backslash), @code{\/} escape sequence @@ -4954,13 +5064,13 @@ characters @samp{a+b}. @cindex @code{\} (backslash), in escape sequences @cindex portability For complete portability, do not use a backslash before any character not -shown in the previous list. +shown in the previous list and that is not an operator. To summarize: @itemize @value{BULLET} @item -The escape sequences in the table above are always processed first, +The escape sequences in the list above are always processed first, for both string constants and regexp constants. This happens very early, as soon as @command{awk} reads your program. @@ -5050,7 +5160,7 @@ are recognized and converted into corresponding real characters as the very first step in processing regexps. Here is a list of metacharacters. All characters that are not escape -sequences and that are not listed in the table stand for themselves: +sequences and that are not listed in the following stand for themselves: @c Use @asis so the docbook comes out ok. Sigh. @table @asis @@ -5107,10 +5217,10 @@ with @samp{A}. @cindex POSIX @command{awk}, period (@code{.})@comma{} using In strict POSIX mode (@pxref{Options}), -@samp{.} does not match the @value{NUL} +@samp{.} does not match the @sc{nul} character, which is a character with all bits equal to zero. -Otherwise, @value{NUL} is just another character. Other versions of @command{awk} -may not be able to match the @value{NUL} character. +Otherwise, @sc{nul} is just another character. Other versions of @command{awk} +may not be able to match the @sc{nul} character. @cindex @code{[]} (square brackets), regexp operator @cindex square brackets (@code{[]}), regexp operator @@ -5175,7 +5285,7 @@ component (e.g., in @samp{ph*}, it applies just to the @samp{h}). To cause @samp{*} to apply to a larger sub-expression, use parentheses: @samp{(ph)*} matches @samp{ph}, @samp{phph}, @samp{phphph} and so on. -Second, @samp{*} finds as many repetititons as possible. If the text +Second, @samp{*} finds as many repetitions as possible. If the text to be matched is @samp{phhhhhhhhhhhhhhooey}, @samp{ph*} matches all of the @samp{h}s. @@ -5307,7 +5417,7 @@ characters to be matched. @cindex Extended Regular Expressions (EREs) @cindex EREs (Extended Regular Expressions) @cindex @command{egrep} utility -This treatment of @samp{\} in bracket expressions +The treatment of @samp{\} in bracket expressions is compatible with other @command{awk} implementations and is also mandated by POSIX. The regular expressions in @command{awk} are a superset @@ -5424,11 +5534,11 @@ Consider the following: echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' @end example -This example uses the @code{sub()} function (which we haven't discussed yet; -@pxref{String Functions}) -to make a change to the input record. Here, the regexp @code{/a+/} -indicates ``one or more @samp{a} characters,'' and the replacement -text is @samp{<A>}. +This example uses the @code{sub()} function to make a change to the input +record. (@code{sub()} replaces the first instance of any text matched +by the first argument with the string provided as the second argument; +@pxref{String Functions}). Here, the regexp @code{/a+/} indicates ``one +or more @samp{a} characters,'' and the replacement text is @samp{<A>}. The input contains four @samp{a} characters. @command{awk} (and POSIX) regular expressions always match @@ -5539,7 +5649,7 @@ intend a regexp match. @cindex regular expressions, dynamic, with embedded newlines @cindex newlines, in dynamic regexps -Some versions of @command{awk} do not allow the newline +Some older versions of @command{awk} do not allow the newline character to be used inside a bracket expression for a dynamic regexp: @example @@ -5548,7 +5658,7 @@ $ @kbd{awk '$0 ~ "[ \t\n]"'} @error{} ]... @error{} source line number 1 @error{} context is -@error{} >>> <<< +@error{} $0 ~ "[ >>> \t\n]" <<< @end example @cindex newlines, in regexp constants @@ -5730,7 +5840,7 @@ are allowed. Traditional Unix @command{awk} regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (@samp{[[:alnum:]]}, etc.) are supported, -as BWK @command{awk} does support them. +as BWK @command{awk} supports them. Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. @@ -5871,11 +5981,6 @@ Within bracket expressions, POSIX character classes let you specify certain groups of characters in a locale-independent fashion. @item -@command{gawk}'s @code{IGNORECASE} variable lets you control the -case sensitivity of regexp matching. In other @command{awk} -versions, use @code{tolower()} or @code{toupper()}. - -@item Regular expressions match the leftmost longest text in the string being matched. This matters for cases where you need to know the extent of the match, such as for text substitution and when the record separator @@ -5885,6 +5990,11 @@ is a regexp. Matching expressions may use dynamic regexps, that is, string values treated as regular expressions. +@item +@command{gawk}'s @code{IGNORECASE} variable lets you control the +case sensitivity of regexp matching. In other @command{awk} +versions, use @code{tolower()} or @code{toupper()}. + @end itemize @c ENDOFRANGE regexp @@ -5903,7 +6013,7 @@ standard input (by default, this is the keyboard, but often it is a pipe from an command) or from files whose names you specify on the @command{awk} command line. If you specify input files, @command{awk} reads them in order, processing all the data from one before going on to the next. -The name of the current input file can be found in the built-in variable +The name of the current input file can be found in the predefined variable @code{FILENAME} (@pxref{Built-in Variables}). @@ -5951,9 +6061,9 @@ used with it do not have to be named on the @command{awk} command line @cindex @code{FNR} variable @command{awk} divides the input for your program into records and fields. It keeps track of the number of records that have been read so far from -the current input file. This value is stored in a built-in variable -called @code{FNR} which is reset to zero when a new file is started. -Another built-in variable, @code{NR}, records the total number of input +the current input file. This value is stored in a predefined variable +called @code{FNR} which is reset to zero every time a new file is started. +Another predefined variable, @code{NR}, records the total number of input records read so far from all @value{DF}s. It starts at zero, but is never automatically reset to zero. @@ -5971,7 +6081,7 @@ Records are separated by a character called the @dfn{record separator}. By default, the record separator is the newline character. This is why records are, by default, single lines. A different character can be used for the record separator by -assigning the character to the built-in variable @code{RS}. +assigning the character to the predefined variable @code{RS}. @cindex newlines, as record separators @cindex @code{RS} variable @@ -6082,7 +6192,8 @@ Using an unusual character such as @samp{/} is more likely to produce correct behavior in the majority of cases, but there are no guarantees. The moral is: Know Your Data. -There is one unusual case, that occurs when @command{gawk} is +When using regular characters as the record separator, +there is one unusual case that occurs when @command{gawk} is being fully POSIX-compliant (@pxref{Options}). Then, the following (extreme) pipeline prints a surprising @samp{1}: @@ -6171,7 +6282,7 @@ $ @kbd{echo record 1 AAAA record 2 BBBB record 3 |} @noindent The square brackets delineate the contents of @code{RT}, letting you -see the leading and trailing whitespace. The final value of @code{RT} +see the leading and trailing whitespace. The final value of @code{RT} is a newline. @xref{Simple Sed}, for a more useful example of @code{RS} as a regexp and @code{RT}. @@ -6190,7 +6301,7 @@ metacharacters match the beginning and end of a @emph{string}, and not the beginning and end of a @emph{line}. As a result, something like @samp{RS = "^[[:upper:]]"} can only match at the beginning of a file. This is because @command{gawk} views the input file as one long string -that happens to contain newline characters in it. +that happens to contain newline characters. It is thus best to avoid anchor characters in the value of @code{RS}. @end quotation @@ -6200,7 +6311,7 @@ variable are @command{gawk} extensions; they are not available in compatibility mode (@pxref{Options}). In compatibility mode, only the first character of the value of -@code{RS} is used to determine the end of the record. +@code{RS} determines the end of the record. @sidebar @code{RS = "\0"} Is Not Portable @cindex portability, data files as single record @@ -6210,7 +6321,7 @@ a value that you know doesn't occur in the input file. This is hard to do in a general way, such that a program always works for arbitrary input files. -You might think that for text files, the @value{NUL} character, which +You might think that for text files, the @sc{nul} character, which consists of a character with all bits equal to zero, is a good value to use for @code{RS} in this case: @@ -6219,27 +6330,28 @@ BEGIN @{ RS = "\0" @} # whole file becomes one record? @end example @cindex differences in @command{awk} and @command{gawk}, strings, storing -@command{gawk} in fact accepts this, and uses the @value{NUL} +@command{gawk} in fact accepts this, and uses the @sc{nul} character for the record separator. This works for certain special files, such as @file{/proc/environ} on -GNU/Linux systems, where the @value{NUL} character is in fact the record separator. +GNU/Linux systems, where the @sc{nul} character is in fact the record separator. However, this usage is @emph{not} portable to most other @command{awk} implementations. @cindex dark corner, strings, storing Almost all other @command{awk} implementations@footnote{At least that we know about.} store strings internally as C-style strings. C strings use the -@value{NUL} character as the string terminator. In effect, this means that +@sc{nul} character as the string terminator. In effect, this means that @samp{RS = "\0"} is the same as @samp{RS = ""}. @value{DARKCORNER} -It happens that recent versions of @command{mawk} can use the @value{NUL} +It happens that recent versions of @command{mawk} can use the @sc{nul} character as a record separator. However, this is a special case: -@command{mawk} does not allow embedded @value{NUL} characters in strings. +@command{mawk} does not allow embedded @sc{nul} characters in strings. +(This may change in a future version of @command{mawk}.) @cindex records, treating files as @cindex treating files, as single records -@xref{Readfile Function}, for an interesting, portable way to read +@xref{Readfile Function}, for an interesting way to read whole files. If you are using @command{gawk}, see @ref{Extension Sample Readfile}, for another option. @end sidebar @@ -6298,7 +6410,7 @@ field. @cindex @code{NF} variable @cindex fields, number of -@code{NF} is a built-in variable whose value is the number of fields +@code{NF} is a predefined variable whose value is the number of fields in the current record. @command{awk} automatically updates the value of @code{NF} each time it reads a record. No matter how many fields there are, the last field in a record can be represented by @code{$NF}. @@ -6320,15 +6432,11 @@ $ @kbd{awk '$1 ~ /li/ @{ print $0 @}' mail-list} @noindent This example prints each record in the file @file{mail-list} whose first -field contains the string @samp{li}. The operator @samp{~} is called a -@dfn{matching operator} -(@pxref{Regexp Usage}); -it tests whether a string (here, the field @code{$1}) matches a given regular -expression. +field contains the string @samp{li}. -By contrast, the following example -looks for @samp{li} in @emph{the entire record} and prints the first -field and the last field for each matching input record: +By contrast, the following example looks for @samp{li} in @emph{the +entire record} and prints the first and last fields for each matching +input record: @example $ @kbd{awk '/li/ @{ print $1, $NF @}' mail-list} @@ -6391,7 +6499,7 @@ implementations may behave differently.) As mentioned in @ref{Fields}, @command{awk} stores the current record's number of fields in the built-in -variable @code{NF} (also @pxref{Built-in Variables}). The expression +variable @code{NF} (also @pxref{Built-in Variables}). Thus, the expression @code{$NF} is not a special feature---it is the direct consequence of evaluating @code{NF} and using its value as a field number. @@ -6451,8 +6559,8 @@ It is also possible to also assign contents to fields that are out of range. For example: @example -$ awk '@{ $6 = ($5 + $4 + $3 + $2) -> print $6 @}' inventory-shipped +$ @kbd{awk '@{ $6 = ($5 + $4 + $3 + $2)} +> @kbd{ print $6 @}' inventory-shipped} @print{} 168 @print{} 297 @print{} 301 @@ -6541,7 +6649,7 @@ Here is an example: @example $ echo a b c d e f | awk '@{ print "NF =", NF; -> NF = 3; print $0 @}' +> NF = 3; print $0 @}' @print{} NF = 6 @print{} a b c @end example @@ -6549,7 +6657,7 @@ $ echo a b c d e f | awk '@{ print "NF =", NF; @cindex portability, @code{NF} variable@comma{} decrementing @quotation CAUTION Some versions of @command{awk} don't -rebuild @code{$0} when @code{NF} is decremented. Caveat emptor. +rebuild @code{$0} when @code{NF} is decremented. @end quotation Finally, there are times when it is convenient to force @@ -6580,7 +6688,7 @@ record, exactly as it was read from the input. This includes any leading or trailing whitespace, and the exact whitespace (or other characters) that separate the fields. -It is a not-uncommon error to try to change the field separators +It is a common error to try to change the field separators in a record simply by setting @code{FS} and @code{OFS}, and then expecting a plain @samp{print} or @samp{print $0} to print the modified record. @@ -6629,7 +6737,7 @@ is split into three fields: @samp{m}, @samp{@bullet{}g}, and Note the leading spaces in the values of the second and third fields. @cindex troubleshooting, @command{awk} uses @code{FS} not @code{IFS} -The field separator is represented by the built-in variable @code{FS}. +The field separator is represented by the predefined variable @code{FS}. Shell programmers take note: @command{awk} does @emph{not} use the name @code{IFS} that is used by the POSIX-compliant shells (such as the Unix Bourne shell, @command{sh}, or Bash). @@ -6783,9 +6891,10 @@ $ @kbd{echo ' a b c d' | awk '@{ print; $2 = $2; print @}'} The first @code{print} statement prints the record as it was read, with leading whitespace intact. The assignment to @code{$2} rebuilds @code{$0} by concatenating @code{$1} through @code{$NF} together, -separated by the value of @code{OFS}. Because the leading whitespace -was ignored when finding @code{$1}, it is not part of the new @code{$0}. -Finally, the last @code{print} statement prints the new @code{$0}. +separated by the value of @code{OFS} (which is a space by default). +Because the leading whitespace was ignored when finding @code{$1}, +it is not part of the new @code{$0}. Finally, the last @code{print} +statement prints the new @code{$0}. @cindex @code{FS}, containing @code{^} @cindex @code{^} (caret), in @code{FS} @@ -6807,7 +6916,7 @@ also works this way. For example: @example $ @kbd{echo 'xxAA xxBxx C' |} > @kbd{gawk -F '(^x+)|( +)' '@{ for (i = 1; i <= NF; i++)} -> @kbd{printf "-->%s<--\n", $i @}'} +> @kbd{ printf "-->%s<--\n", $i @}'} @print{} --><-- @print{} -->AA<-- @print{} -->xxBxx<-- @@ -6870,15 +6979,10 @@ awk -F, '@var{program}' @var{input-files} @noindent sets @code{FS} to the @samp{,} character. Notice that the option uses an uppercase @samp{F} instead of a lowercase @samp{f}. The latter -option (@option{-f}) specifies a file -containing an @command{awk} program. Case is significant in command-line -options: -the @option{-F} and @option{-f} options have nothing to do with each other. -You can use both options at the same time to set the @code{FS} variable -@emph{and} get an @command{awk} program from a file. +option (@option{-f}) specifies a file containing an @command{awk} program. The value used for the argument to @option{-F} is processed in exactly the -same way as assignments to the built-in variable @code{FS}. +same way as assignments to the predefined variable @code{FS}. Any special characters in the field separator must be escaped appropriately. For example, to use a @samp{\} as the field separator on the command line, you would have to type: @@ -6989,7 +7093,7 @@ to @code{FS} (the backslash is stripped). This creates a regexp meaning If instead you want fields to be separated by a literal period followed by any single character, use @samp{FS = "\\.."}. -The following table summarizes how fields are split, based on the value +The following list summarizes how fields are split, based on the value of @code{FS} (@samp{==} means ``is equal to''): @table @code @@ -7010,8 +7114,7 @@ Leading and trailing matches of @var{regexp} delimit empty fields. @item FS == "" Each individual character in the record becomes a separate field. -(This is a @command{gawk} extension; it is not specified by the -POSIX standard.) +(This is a common extension; it is not specified by the POSIX standard.) @end table @sidebar Changing @code{FS} Does Not Affect the Fields @@ -7463,7 +7566,7 @@ BEGIN @{ RS = "" ; FS = "\n" @} Running the program produces the following output: @example -$ awk -f addrs.awk addresses +$ @kbd{awk -f addrs.awk addresses} @print{} Name is: Jane Doe @print{} Address is: 123 Main Street @print{} City and State are: Anywhere, SE 12345-6789 @@ -7475,12 +7578,9 @@ $ awk -f addrs.awk addresses @dots{} @end example -@xref{Labels Program}, for a more realistic -program that deals with address lists. -The following -table -summarizes how records are split, based on the -value of +@xref{Labels Program}, for a more realistic program that deals with +address lists. The following list summarizes how records are split, +based on the value of @ifinfo @code{RS}. (@samp{==} means ``is equal to.'') @@ -7515,8 +7615,8 @@ POSIX standard.) @cindex @command{gawk}, @code{RT} variable in @cindex @code{RT} variable -In all cases, @command{gawk} sets @code{RT} to the input text that matched the -value specified by @code{RS}. +If not in compatibility mode (@pxref{Options}), @command{gawk} sets +@code{RT} to the input text that matched the value specified by @code{RS}. But if the input file ended without any text that matches @code{RS}, then @command{gawk} sets @code{RT} to the null string. @c ENDOFRANGE recm @@ -7614,9 +7714,7 @@ processing on the next record @emph{right now}. For example: while (j == 0) @{ # get more text if (getline <= 0) @{ - m = "unexpected EOF or error" - m = (m ": " ERRNO) - print m > "/dev/stderr" + print("unexpected EOF or error:", ERRNO) > "/dev/stderr" exit @} # build up the line using string concatenation @@ -7775,7 +7873,7 @@ from the file @var{file}, and put it in the variable @var{var}. As above, @var{file} is a string-valued expression that specifies the file from which to read. -In this version of @code{getline}, none of the built-in variables are +In this version of @code{getline}, none of the predefined variables are changed and the record is not split into fields. The only variable changed is @var{var}.@footnote{This is not quite true. @code{RT} could be changed if @code{RS} is a regular expression.} @@ -7885,7 +7983,7 @@ bletch @end example @noindent -Notice that this program ran the command @command{who} and printed the previous result. +Notice that this program ran the command @command{who} and printed the result. (If you try this program yourself, you will of course get different results, depending upon who is logged in on your system.) @@ -7910,7 +8008,7 @@ Unfortunately, @command{gawk} has not been consistent in its treatment of a construct like @samp{@w{"echo "} "date" | getline}. Most versions, including the current version, treat it at as @samp{@w{("echo "} "date") | getline}. -(This how BWK @command{awk} behaves.) +(This is also how BWK @command{awk} behaves.) Some versions changed and treated it as @samp{@w{"echo "} ("date" | getline)}. (This is how @command{mawk} behaves.) @@ -7937,8 +8035,8 @@ BEGIN @{ @} @end example -In this version of @code{getline}, none of the built-in variables are -changed and the record is not split into fields. +In this version of @code{getline}, none of the predefined variables are +changed and the record is not split into fields. However, @code{RT} is set. @ifinfo @c Thanks to Paul Eggert for initial wording here @@ -7999,7 +8097,7 @@ When you use @samp{@var{command} |& getline @var{var}}, the output from the coprocess @var{command} is sent through a two-way pipe to @code{getline} and into the variable @var{var}. -In this version of @code{getline}, none of the built-in variables are +In this version of @code{getline}, none of the predefined variables are changed and the record is not split into fields. The only variable changed is @var{var}. However, @code{RT} is set. @@ -8046,7 +8144,7 @@ causes @command{awk} to set the value of @code{FILENAME}. Normally, @code{FILENAME} does not have a value inside @code{BEGIN} rules, because you have not yet started to process the command-line @value{DF}s. @value{DARKCORNER} -(@xref{BEGIN/END}, +(See @ref{BEGIN/END}; also @pxref{Auto-set}.) @item @@ -8093,7 +8191,7 @@ end of file is encountered, before the element in @code{a} is assigned? @command{gawk} treats @code{getline} like a function call, and evaluates the expression @samp{a[++c]} before attempting to read from @file{f}. However, some versions of @command{awk} only evaluate the expression once they -know that there is a string value to be assigned. Caveat Emptor. +know that there is a string value to be assigned. @end itemize @node Getline Summary @@ -8102,22 +8200,22 @@ know that there is a string value to be assigned. Caveat Emptor. @ref{table-getline-variants} summarizes the eight variants of @code{getline}, -listing which built-in variables are set by each one, +listing which predefined variables are set by each one, and whether the variant is standard or a @command{gawk} extension. -Note: for each variant, @command{gawk} sets the @code{RT} built-in variable. +Note: for each variant, @command{gawk} sets the @code{RT} predefined variable. @float Table,table-getline-variants @caption{@code{getline} Variants and What They Set} @multitable @columnfractions .33 .38 .27 -@headitem Variant @tab Effect @tab Standard / Extension -@item @code{getline} @tab Sets @code{$0}, @code{NF}, @code{FNR}, @code{NR}, and @code{RT} @tab Standard -@item @code{getline} @var{var} @tab Sets @var{var}, @code{FNR}, @code{NR}, and @code{RT} @tab Standard -@item @code{getline <} @var{file} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Standard -@item @code{getline @var{var} < @var{file}} @tab Sets @var{var} and @code{RT} @tab Standard -@item @var{command} @code{| getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Standard -@item @var{command} @code{| getline} @var{var} @tab Sets @var{var} and @code{RT} @tab Standard -@item @var{command} @code{|& getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab Extension -@item @var{command} @code{|& getline} @var{var} @tab Sets @var{var} and @code{RT} @tab Extension +@headitem Variant @tab Effect @tab @command{awk} / @command{gawk} +@item @code{getline} @tab Sets @code{$0}, @code{NF}, @code{FNR}, @code{NR}, and @code{RT} @tab @command{awk} +@item @code{getline} @var{var} @tab Sets @var{var}, @code{FNR}, @code{NR}, and @code{RT} @tab @command{awk} +@item @code{getline <} @var{file} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{awk} +@item @code{getline @var{var} < @var{file}} @tab Sets @var{var} and @code{RT} @tab @command{awk} +@item @var{command} @code{| getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{awk} +@item @var{command} @code{| getline} @var{var} @tab Sets @var{var} and @code{RT} @tab @command{awk} +@item @var{command} @code{|& getline} @tab Sets @code{$0}, @code{NF}, and @code{RT} @tab @command{gawk} +@item @var{command} @code{|& getline} @var{var} @tab Sets @var{var} and @code{RT} @tab @command{gawk} @end multitable @end float @c ENDOFRANGE getl @@ -8134,7 +8232,7 @@ This @value{SECTION} describes a feature that is specific to @command{gawk}. You may specify a timeout in milliseconds for reading input from the keyboard, a pipe, or two-way communication, including TCP/IP sockets. This can be done on a per input, command or connection basis, by setting a special element -in the @code{PROCINFO} (@pxref{Auto-set}) array: +in the @code{PROCINFO} array (@pxref{Auto-set}): @example PROCINFO["input_name", "READ_TIMEOUT"] = @var{timeout in milliseconds} @@ -8166,7 +8264,7 @@ while ((getline < "/dev/stdin") > 0) @command{gawk} terminates the read operation if input does not arrive after waiting for the timeout period, returns failure -and sets the @code{ERRNO} variable to an appropriate string value. +and sets @code{ERRNO} to an appropriate string value. A negative or zero value for the timeout is the same as specifying no timeout at all. @@ -8273,6 +8371,10 @@ The possibilities are as follows: @end multitable @item +@code{FNR} indicates how many records have been read from the current input file; +@code{NR} indicates how many records have been read in total. + +@item @command{gawk} sets @code{RT} to the text matched by @code{RS}. @item @@ -8283,7 +8385,7 @@ fields there are. The default way to split fields is between whitespace characters. @item -Fields may be referenced using a variable, as in @samp{$NF}. Fields +Fields may be referenced using a variable, as in @code{$NF}. Fields may also be assigned values, which causes the value of @code{$0} to be recomputed when it is later referenced. Assigning to a field with a number greater than @code{NF} creates the field and rebuilds the record, using @@ -8293,16 +8395,17 @@ thing. Decrementing @code{NF} throws away fields and rebuilds the record. @item Field splitting is more complicated than record splitting. -@multitable @columnfractions .40 .40 .20 +@multitable @columnfractions .40 .45 .15 @headitem Field separator value @tab Fields are split @dots{} @tab @command{awk} / @command{gawk} @item @code{FS == " "} @tab On runs of whitespace @tab @command{awk} @item @code{FS == @var{any single character}} @tab On that character @tab @command{awk} @item @code{FS == @var{regexp}} @tab On text matching the regexp @tab @command{awk} @item @code{FS == ""} @tab Each individual character is a separate field @tab @command{gawk} @item @code{FIELDWIDTHS == @var{list of columns}} @tab Based on character position @tab @command{gawk} -@item @code{FPAT == @var{regexp}} @tab On text around text matching the regexp @tab @command{gawk} +@item @code{FPAT == @var{regexp}} @tab On the text surrounding text matching the regexp @tab @command{gawk} @end multitable +@item Using @samp{FS = "\n"} causes the entire record to be a single field (assuming that newlines separate records). @@ -8311,11 +8414,11 @@ Using @samp{FS = "\n"} causes the entire record to be a single field This can also be done using command-line variable assignment. @item -@code{PROCINFO["FS"]} can be used to see how fields are being split. +Use @code{PROCINFO["FS"]} to see how fields are being split. @item Use @code{getline} in its various forms to read additional records, -from the default input stream, from a file, or from a pipe or co-process. +from the default input stream, from a file, or from a pipe or coprocess. @item Use @code{PROCINFO[@var{file}, "READ_TIMEOUT"]} to cause reads to timeout @@ -8384,6 +8487,7 @@ and discusses the @code{close()} built-in function. * Printf:: The @code{printf} statement. * Redirection:: How to redirect output to multiple files and pipes. +* Special FD:: Special files for I/O. * Special Files:: File name interpretation in @command{gawk}. @command{gawk} allows access to inherited file descriptors. @@ -8395,7 +8499,7 @@ and discusses the @code{close()} built-in function. @node Print @section The @code{print} Statement -The @code{print} statement is used for producing output with simple, standardized +Use the @code{print} statement to produce output with simple, standardized formatting. You specify only the strings or numbers to print, in a list separated by commas. They are output, separated by single spaces, followed by a newline. The statement looks like this: @@ -8419,7 +8523,7 @@ expression. Numeric values are converted to strings and then printed. @cindex text, printing The simple statement @samp{print} with no items is equivalent to @samp{print $0}: it prints the entire current record. To print a blank -line, use @samp{print ""}, where @code{""} is the empty string. +line, use @samp{print ""}. To print a fixed piece of text, use a string constant, such as @w{@code{"Don't Panic"}}, as one item. If you forget to use the double-quote characters, your text is taken as an @command{awk} @@ -8427,8 +8531,8 @@ expression, and you will probably get an error. Keep in mind that a space is printed between any two items. Note that the @code{print} statement is a statement and not an -expression---you can't use it the pattern part of a pattern-action -statement, for example. +expression---you can't use it in the pattern part of a +@var{pattern}-@var{action} statement, for example. @node Print Examples @section @code{print} Statement Examples @@ -8439,9 +8543,22 @@ newline, the newline is output along with the rest of the string. A single @code{print} statement can make any number of lines this way. @cindex newlines, printing -The following is an example of printing a string that contains embedded newlines +The following is an example of printing a string that contains embedded +@ifinfo +newlines (the @samp{\n} is an escape sequence, used to represent the newline character; @pxref{Escape Sequences}): +@end ifinfo +@ifhtml +newlines +(the @samp{\n} is an escape sequence, used to represent the newline +character; @pxref{Escape Sequences}): +@end ifhtml +@ifnotinfo +@ifnothtml +newlines: +@end ifnothtml +@end ifnotinfo @example $ @kbd{awk 'BEGIN @{ print "line one\nline two\nline three" @}'} @@ -8545,7 +8662,7 @@ of items separated by commas. In the output, the items are normally separated by single spaces. However, this doesn't need to be the case; a single space is simply the default. Any string of characters may be used as the @dfn{output field separator} by setting the -built-in variable @code{OFS}. The initial value of this variable +predefined variable @code{OFS}. The initial value of this variable is the string @w{@code{" "}}---that is, a single space. The output from an entire @code{print} statement is called an @@ -8621,13 +8738,13 @@ more fully in @cindexawkfunc{sprintf} @cindex @code{OFMT} variable @cindex output, format specifier@comma{} @code{OFMT} -The built-in variable @code{OFMT} contains the default format specification +The predefined variable @code{OFMT} contains the format specification that @code{print} uses with @code{sprintf()} when it wants to convert a number to a string for printing. The default value of @code{OFMT} is @code{"%.6g"}. The way @code{print} prints numbers can be changed -by supplying different format specifications -as the value of @code{OFMT}, as shown in the following example: +by supplying a different format specification +for the value of @code{OFMT}, as shown in the following example: @example $ @kbd{awk 'BEGIN @{} @@ -8657,9 +8774,7 @@ With @code{printf} you can specify the width to use for each item, as well as various formatting choices for numbers (such as what output base to use, whether to print an exponent, whether to print a sign, and how many digits to print -after the decimal point). You do this by supplying a string, called -the @dfn{format string}, that controls how and where to print the other -arguments. +after the decimal point). @menu * Basic Printf:: Syntax of the @code{printf} statement. @@ -8679,10 +8794,10 @@ printf @var{format}, @var{item1}, @var{item2}, @dots{} @end example @noindent -The entire list of arguments may optionally be enclosed in parentheses. The -parentheses are necessary if any of the item expressions use the @samp{>} -relational operator; otherwise, it can be confused with an output redirection -(@pxref{Redirection}). +As print @code{print}, the entire list of arguments may optionally be +enclosed in parentheses. Here too, the parentheses are necessary if any +of the item expressions use the @samp{>} relational operator; otherwise, +it can be confused with an output redirection (@pxref{Redirection}). @cindex format specifiers The difference between @code{printf} and @code{print} is the @var{format} @@ -8705,10 +8820,10 @@ on @code{printf} statements. For example: @example $ @kbd{awk 'BEGIN @{} > @kbd{ORS = "\nOUCH!\n"; OFS = "+"} -> @kbd{msg = "Dont Panic!"} +> @kbd{msg = "Don\47t Panic!"} > @kbd{printf "%s\n", msg} > @kbd{@}'} -@print{} Dont Panic! +@print{} Don't Panic! @end example @noindent @@ -8730,7 +8845,7 @@ the field width. Here is a list of the format-control letters: @c @asis for docbook to come out right @table @asis @item @code{%c} -Print a number as an ASCII character; thus, @samp{printf "%c", +Print a number as a character; thus, @samp{printf "%c", 65} outputs the letter @samp{A}. The output for a string value is the first character of the string. @@ -8756,7 +8871,7 @@ a single byte (0--255). @item @code{%d}, @code{%i} Print a decimal integer. The two control letters are equivalent. -(The @samp{%i} specification is for compatibility with ISO C.) +(The @code{%i} specification is for compatibility with ISO C.) @item @code{%e}, @code{%E} Print a number in scientific (exponential) notation; @@ -8771,7 +8886,7 @@ prints @samp{1.950e+03}, with a total of four significant figures, three of which follow the decimal point. (The @samp{4.3} represents two modifiers, discussed in the next @value{SUBSECTION}.) -@samp{%E} uses @samp{E} instead of @samp{e} in the output. +@code{%E} uses @samp{E} instead of @samp{e} in the output. @item @code{%f} Print a number in floating-point notation. @@ -8797,16 +8912,16 @@ The special ``not a number'' value formats as @samp{-nan} or @samp{nan} (@pxref{Math Definitions}). @item @code{%F} -Like @samp{%f} but the infinity and ``not a number'' values are spelled +Like @code{%f} but the infinity and ``not a number'' values are spelled using uppercase letters. -The @samp{%F} format is a POSIX extension to ISO C; not all systems -support it. On those that don't, @command{gawk} uses @samp{%f} instead. +The @code{%F} format is a POSIX extension to ISO C; not all systems +support it. On those that don't, @command{gawk} uses @code{%f} instead. @item @code{%g}, @code{%G} Print a number in either scientific notation or in floating-point notation, whichever uses fewer characters; if the result is printed in -scientific notation, @samp{%G} uses @samp{E} instead of @samp{e}. +scientific notation, @code{%G} uses @samp{E} instead of @samp{e}. @item @code{%o} Print an unsigned octal integer @@ -8822,7 +8937,7 @@ are floating-point; it is provided primarily for compatibility with C.) @item @code{%x}, @code{%X} Print an unsigned hexadecimal integer; -@samp{%X} uses the letters @samp{A} through @samp{F} +@code{%X} uses the letters @samp{A} through @samp{F} instead of @samp{a} through @samp{f} (@pxref{Nondecimal-numbers}). @@ -8837,7 +8952,7 @@ argument and it ignores any modifiers. @quotation NOTE When using the integer format-control letters for values that are outside the range of the widest C integer type, @command{gawk} switches to -the @samp{%g} format specifier. If @option{--lint} is provided on the +the @code{%g} format specifier. If @option{--lint} is provided on the command line (@pxref{Options}), @command{gawk} warns about this. Other versions of @command{awk} may print invalid values or do something else entirely. @@ -8853,7 +8968,7 @@ values or do something else entirely. A format specification can also include @dfn{modifiers} that can control how much of the item's value is printed, as well as how much space it gets. The modifiers come between the @samp{%} and the format-control letter. -We will use the bullet symbol ``@bullet{}'' in the following examples to +We use the bullet symbol ``@bullet{}'' in the following examples to represent spaces in the output. Here are the possible modifiers, in the order in which they may appear: @@ -8884,7 +8999,7 @@ It is in fact a @command{gawk} extension, intended for use in translating messages at runtime. @xref{Printf Ordering}, which describes how and why to use positional specifiers. -For now, we will not use them. +For now, we ignore them. @item - The minus sign, used before the width modifier (see later on in @@ -8912,15 +9027,15 @@ to format is positive. The @samp{+} overrides the space modifier. @item # Use an ``alternate form'' for certain control letters. -For @samp{%o}, supply a leading zero. -For @samp{%x} and @samp{%X}, supply a leading @samp{0x} or @samp{0X} for +For @code{%o}, supply a leading zero. +For @code{%x} and @code{%X}, supply a leading @code{0x} or @samp{0X} for a nonzero result. -For @samp{%e}, @samp{%E}, @samp{%f}, and @samp{%F}, the result always +For @code{%e}, @code{%E}, @code{%f}, and @code{%F}, the result always contains a decimal point. -For @samp{%g} and @samp{%G}, trailing zeros are not removed from the result. +For @code{%g} and @code{%G}, trailing zeros are not removed from the result. @item 0 -A leading @samp{0} (zero) acts as a flag that indicates that output should be +A leading @samp{0} (zero) acts as a flag indicating that output should be padded with zeros instead of spaces. This applies only to the numeric output formats. This flag only has an effect when the field width is wider than the @@ -9106,7 +9221,7 @@ the @command{awk} program: @example awk 'BEGIN @{ print "Name Number" print "---- ------" @} - @{ printf "%-10s %s\n", $1, $2 @}' mail-list + @{ printf "%-10s %s\n", $1, $2 @}' mail-list @end example The above example mixes @code{print} and @code{printf} statements in @@ -9116,7 +9231,7 @@ same results: @example awk 'BEGIN @{ printf "%-10s %s\n", "Name", "Number" printf "%-10s %s\n", "----", "------" @} - @{ printf "%-10s %s\n", $1, $2 @}' mail-list + @{ printf "%-10s %s\n", $1, $2 @}' mail-list @end example @noindent @@ -9131,7 +9246,7 @@ emphasized by storing it in a variable, like this: awk 'BEGIN @{ format = "%-10s %s\n" printf format, "Name", "Number" printf format, "----", "------" @} - @{ printf format, $1, $2 @}' mail-list + @{ printf format, $1, $2 @}' mail-list @end example @c ENDOFRANGE printfs @@ -9152,7 +9267,7 @@ This is called @dfn{redirection}. @quotation NOTE When @option{--sandbox} is specified (@pxref{Options}), -redirecting output to files and pipes is disabled. +redirecting output to files, pipes and coprocesses is disabled. @end quotation A redirection appears after the @code{print} or @code{printf} statement. @@ -9249,17 +9364,11 @@ in an @command{awk} script run periodically for system maintenance: @example report = "mail bug-system" -print "Awk script failed:", $0 | report -m = ("at record number " FNR " of " FILENAME) -print m | report +print("Awk script failed:", $0) | report +print("at record number", FNR, "of", FILENAME) | report close(report) @end example -The message is built using string concatenation and saved in the variable -@code{m}. It's then sent down the pipeline to the @command{mail} program. -(The parentheses group the items to concatenate---see -@ref{Concatenation}.) - The @code{close()} function is called here because it's a good idea to close the pipe as soon as all the intended output has been sent to it. @xref{Close Files And Pipes}, @@ -9360,27 +9469,15 @@ uppercase characters converted to lowercase The program builds up a list of command lines, using the @command{mv} utility to rename the files. It then sends the list to the shell for execution. + +@xref{Shell Quoting}, for a function that can help in generating +command lines to be fed to the shell. @end sidebar @c ENDOFRANGE outre @c ENDOFRANGE reout -@node Special Files -@section Special @value{FFN}s in @command{gawk} -@c STARTOFRANGE gfn -@cindex @command{gawk}, file names in - -@command{gawk} provides a number of special @value{FN}s that it interprets -internally. These @value{FN}s provide access to standard file descriptors -and TCP/IP networking. - -@menu -* Special FD:: Special files for I/O. -* Special Network:: Special files for network communications. -* Special Caveats:: Things to watch out for. -@end menu - @node Special FD -@subsection Special Files for Standard Descriptors +@section Special Files for Standard Pre-Opened Data Streams @cindex standard input @cindex input, standard @cindex standard output @@ -9391,9 +9488,12 @@ and TCP/IP networking. @cindex files, descriptors, See file descriptors Running programs conventionally have three input and output streams -already available to them for reading and writing. These are known as -the @dfn{standard input}, @dfn{standard output}, and @dfn{standard error -output}. These streams are, by default, connected to your keyboard and screen, but +already available to them for reading and writing. These are known +as the @dfn{standard input}, @dfn{standard output}, and @dfn{standard +error output}. These open streams (and any other open file or pipe) +are often referred to by the technical term @dfn{file descriptors}. + +These streams are, by default, connected to your keyboard and screen, but they are often redirected with the shell, via the @samp{<}, @samp{<<}, @samp{>}, @samp{>>}, @samp{>&}, and @samp{|} operators. Standard error is typically used for writing error messages; the reason there are two separate @@ -9402,7 +9502,7 @@ redirected separately. @cindex differences in @command{awk} and @command{gawk}, error messages @cindex error handling -In other implementations of @command{awk}, the only way to write an error +In traditional implementations of @command{awk}, the only way to write an error message to standard error in an @command{awk} program is as follows: @example @@ -9428,19 +9528,19 @@ that is connected to your keyboard and screen. It represents the ``terminal,''@footnote{The ``tty'' in @file{/dev/tty} stands for ``Teletype,'' a serial terminal.} which on modern systems is a keyboard and screen, not a serial console.) -This usually has the same effect but not always: although the +This generally has the same effect but not always: although the standard error stream is usually the screen, it can be redirected; when that happens, writing to the screen is not correct. In fact, if @command{awk} is run from a background job, it may not have a terminal at all. Then opening @file{/dev/tty} fails. -@command{gawk} provides special @value{FN}s for accessing the three standard -streams. @value{COMMONEXT} It also provides syntax for accessing -any other inherited open files. If the @value{FN} matches -one of these special names when @command{gawk} redirects input or output, -then it directly uses the stream that the @value{FN} stands for. -These special @value{FN}s work for all operating systems that @command{gawk} +@command{gawk}, BWK @command{awk} and @command{mawk} provide +special @value{FN}s for accessing the three standard streams. +If the @value{FN} matches one of these special names when @command{gawk} +(or one of the others) redirects input or output, then it directly uses +the descriptor that the @value{FN} stands for. These special +@value{FN}s work for all operating systems that @command{gawk} has been ported to, not just those that are POSIX-compliant: @cindex common extensions, @code{/dev/stdin} special file @@ -9462,19 +9562,10 @@ The standard output (file descriptor 1). @item /dev/stderr The standard error output (file descriptor 2). - -@item /dev/fd/@var{N} -The file associated with file descriptor @var{N}. Such a file must -be opened by the program initiating the @command{awk} execution (typically -the shell). Unless special pains are taken in the shell from which -@command{gawk} is invoked, only descriptors 0, 1, and 2 are available. @end table -The @value{FN}s @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} -are aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and @file{/dev/fd/2}, -respectively. However, they are more self-explanatory. -The proper way to write an error message in a @command{gawk} program -is to use @file{/dev/stderr}, like this: +With these facilities, +the proper way to write an error message then becomes: @example print "Serious error detected!" > "/dev/stderr" @@ -9486,14 +9577,51 @@ Like any other redirection, the value must be a string. It is a common error to omit the quotes, which leads to confusing results. -Finally, using the @code{close()} function on a @value{FN} of the +@command{gawk} does not treat these @value{FN}s as special when +in POSIX compatibility mode. However, since BWK @command{awk} +supports them, @command{gawk} does support them even when +invoked with the @option{--traditional} option (@pxref{Options}). + +@node Special Files +@section Special @value{FFN}s in @command{gawk} +@c STARTOFRANGE gfn +@cindex @command{gawk}, file names in + +Besides access to standard input, stanard output, and standard error, +@command{gawk} provides access to any open file descriptor. +Additionally, there are special @value{FN}s reserved for +TCP/IP networking. + +@menu +* Other Inherited Files:: Accessing other open files with + @command{gawk}. +* Special Network:: Special files for network communications. +* Special Caveats:: Things to watch out for. +@end menu + +@node Other Inherited Files +@subsection Accessing Other Open Files With @command{gawk} + +Besides the @code{/dev/stdin}, @code{/dev/stdout}, and @code{/dev/stderr} +special @value{FN}s mentioned earlier, @command{gawk} provides syntax +for accessing any other inherited open file: + +@table @file +@item /dev/fd/@var{N} +The file associated with file descriptor @var{N}. Such a file must +be opened by the program initiating the @command{awk} execution (typically +the shell). Unless special pains are taken in the shell from which +@command{gawk} is invoked, only descriptors 0, 1, and 2 are available. +@end table + +The @value{FN}s @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} +are essentially aliases for @file{/dev/fd/0}, @file{/dev/fd/1}, and +@file{/dev/fd/2}, respectively. However, those names are more self-explanatory. + +Note that using @code{close()} on a @value{FN} of the form @code{"/dev/fd/@var{N}"}, for file descriptor numbers above two, does actually close the given file descriptor. -The @file{/dev/stdin}, @file{/dev/stdout}, and @file{/dev/stderr} -special files are also recognized internally by several other -versions of @command{awk}. - @node Special Network @subsection Special Files for Network Communications @cindex networks, support for @@ -9522,15 +9650,20 @@ Full discussion is delayed until @node Special Caveats @subsection Special @value{FFN} Caveats -Here is a list of things to bear in mind when using the +Here are some things to bear in mind when using the special @value{FN}s that @command{gawk} provides: @itemize @value{BULLET} @cindex compatibility mode (@command{gawk}), file names @cindex file names, in compatibility mode @item -Recognition of these special @value{FN}s is disabled if @command{gawk} is in -compatibility mode (@pxref{Options}). +Recognition of the @value{FN}s for the three standard pre-opened +files is disabled only in POSIX mode. + +@item +Recognition of the other special @value{FN}s is disabled if @command{gawk} is in +compatibility mode (either @option{--traditional} or @option{--posix}; +@pxref{Options}). @item @command{gawk} @emph{always} @@ -9700,7 +9833,8 @@ to a string indicating the error. Note also that @samp{close(FILENAME)} has no ``magic'' effects on the implicit loop that reads through the files named on the command line. It is, more likely, a close of a file that was never opened with a -redirection, so @command{awk} silently does nothing. +redirection, so @command{awk} silently does nothing, except return +a negative value. @cindex @code{|} (vertical bar), @code{|&} operator (I/O), pipes@comma{} closing When using the @samp{|&} operator to communicate with a coprocess, @@ -9712,10 +9846,10 @@ the first argument is the name of the command or special file used to start the coprocess. The second argument should be a string, with either of the values @code{"to"} or @code{"from"}. Case does not matter. -As this is an advanced feature, a more complete discussion is +As this is an advanced feature, discussion is delayed until @ref{Two-way I/O}, -which discusses it in more detail and gives an example. +which describes it in more detail and gives an example. @sidebar Using @code{close()}'s Return Value @cindex dark corner, @code{close()} function @@ -9741,7 +9875,7 @@ retval = close(command) # syntax error in many Unix awks The return value is @minus{}1 if the argument names something that was never opened with a redirection, or if there is a system problem closing the file or process. -In these cases, @command{gawk} sets the built-in variable +In these cases, @command{gawk} sets the predefined variable @code{ERRNO} to a string describing the problem. In @command{gawk}, @@ -9787,15 +9921,15 @@ that modify the behavior of the format control letters. @item Output from both @code{print} and @code{printf} may be redirected to -files, pipes, and co-processes. +files, pipes, and coprocesses. @item @command{gawk} provides special file names for access to standard input, output and error, and for network communications. @item -Use @code{close()} to close open file, pipe and co-process redirections. -For co-processes, it is possible to close only one direction of the +Use @code{close()} to close open file, pipe and coprocess redirections. +For coprocesses, it is possible to close only one direction of the communications. @end itemize @@ -9929,7 +10063,7 @@ double-quotation marks. For example: @cindex strings, length limitations represents the string whose contents are @samp{parrot}. Strings in @command{gawk} can be of any length, and they can contain any of the possible -eight-bit ASCII characters including ASCII @value{NUL} (character code zero). +eight-bit ASCII characters including ASCII @sc{nul} (character code zero). Other @command{awk} implementations may have difficulty with some character codes. @@ -10080,7 +10214,7 @@ if (/barfly/ || /camelot/) @noindent are exactly equivalent. One rather bizarre consequence of this rule is that the following -Boolean expression is valid, but does not do what the user probably +Boolean expression is valid, but does not do what its author probably intended: @example @@ -10126,10 +10260,9 @@ Modern implementations of @command{awk}, including @command{gawk}, allow the third argument of @code{split()} to be a regexp constant, but some older implementations do not. @value{DARKCORNER} -This can lead to confusion when attempting to use regexp constants -as arguments to user-defined functions -(@pxref{User-defined}). -For example: +Because some built-in functions accept regexp constants as arguments, +it can be confusing when attempting to use regexp constants as arguments +to user-defined functions (@pxref{User-defined}). For example: @example function mysub(pat, repl, str, global) @@ -10197,24 +10330,24 @@ variable's current value. Variables are given new values with @dfn{decrement operators}. @xref{Assignment Ops}. In addition, the @code{sub()} and @code{gsub()} functions can -change a variable's value, and the @code{match()}, @code{patsplit()} -and @code{split()} functions can change the contents of their +change a variable's value, and the @code{match()}, @code{split()} +and @code{patsplit()} functions can change the contents of their array parameters. @xref{String Functions}. @cindex variables, built-in @cindex variables, initializing A few variables have special built-in meanings, such as @code{FS} (the field separator), and @code{NF} (the number of fields in the current input -record). @xref{Built-in Variables}, for a list of the built-in variables. -These built-in variables can be used and assigned just like all other +record). @xref{Built-in Variables}, for a list of the predefined variables. +These predefined variables can be used and assigned just like all other variables, but their values are also used or changed automatically by -@command{awk}. All built-in variables' names are entirely uppercase. +@command{awk}. All predefined variables' names are entirely uppercase. Variables in @command{awk} can be assigned either numeric or string values. The kind of value a variable holds can change over the life of a program. By default, variables are initialized to the empty string, which is zero if converted to a number. There is no need to explicitly -``initialize'' a variable in @command{awk}, +initialize a variable in @command{awk}, which is what you would do in C and in most other traditional languages. @node Assignment Options @@ -10334,7 +10467,7 @@ Strings that can't be interpreted as valid numbers convert to zero. @cindex @code{CONVFMT} variable The exact manner in which numbers are converted into strings is controlled -by the @command{awk} built-in variable @code{CONVFMT} (@pxref{Built-in Variables}). +by the @command{awk} predefined variable @code{CONVFMT} (@pxref{Built-in Variables}). Numbers are converted using the @code{sprintf()} function with @code{CONVFMT} as the format specifier @@ -10422,8 +10555,8 @@ $ @kbd{echo 4,321 | LC_ALL=en_DK.utf-8 gawk '@{ print $1 + 1 @}'} @noindent The @code{en_DK.utf-8} locale is for English in Denmark, where the comma acts as the decimal point separator. In the normal @code{"C"} locale, @command{gawk} -treats @samp{4,321} as @samp{4}, while in the Danish locale, it's treated -as the full number, 4.321. +treats @samp{4,321} as 4, while in the Danish locale, it's treated +as the full number including the fractional part, 4.321. Some earlier versions of @command{gawk} fully complied with this aspect of the standard. However, many users in non-English locales complained @@ -10974,7 +11107,7 @@ awk '/[=]=/' /dev/null @end example @command{gawk} does not have this problem; BWK @command{awk} -and @command{mawk} also do not (@pxref{Other Versions}). +and @command{mawk} also do not. @end sidebar @c ENDOFRANGE exas @c ENDOFRANGE opas @@ -11227,7 +11360,7 @@ attribute. @item Fields, @code{getline} input, @code{FILENAME}, @code{ARGV} elements, @code{ENVIRON} elements, and the elements of an array created by -@code{patsplit()}, @code{split()} and @code{match()} that are numeric +@code{match()}, @code{split()} and @code{patsplit()} that are numeric strings have the @var{strnum} attribute. Otherwise, they have the @var{string} attribute. Uninitialized variables also have the @var{strnum} attribute. @@ -11382,22 +11515,23 @@ Thus, the six-character input string @w{@samp{ +3.14}} receives the The following examples print @samp{1} when the comparison between the two different constants is true, @samp{0} otherwise: +@c 22.9.2014: Tested with mawk and BWK awk, got same results. @example -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == " +3.14" @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == " +3.14") @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == "+3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == "+3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == "3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == "3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $0 == 3.14 @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($0 == 3.14) @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == " +3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == " +3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == "+3.14" @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == "+3.14") @}'} @ii{True} @print{} 1 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == "3.14" @}'} @ii{False} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == "3.14") @}'} @ii{False} @print{} 0 -$ @kbd{echo ' +3.14' | gawk '@{ print $1 == 3.14 @}'} @ii{True} +$ @kbd{echo ' +3.14' | awk '@{ print($1 == 3.14) @}'} @ii{True} @print{} 1 @end example @@ -11471,9 +11605,8 @@ part of the test always succeeds. Because the operators are so similar, this kind of error is very difficult to spot when scanning the source code. -@cindex @command{gawk}, comparison operators and -The following table of expressions illustrates the kind of comparison -@command{gawk} performs, as well as what the result of the comparison is: +The following list of expressions illustrates the kinds of comparisons +@command{awk} performs, as well as what the result of each comparison is: @table @code @item 1.5 <= 2.0 @@ -11546,7 +11679,7 @@ dynamic regexp (@pxref{Regexp Usage}; also @cindex @command{awk}, regexp constants and @cindex regexp constants -In modern implementations of @command{awk}, a constant regular +A constant regular expression in slashes by itself is also an expression. The regexp @code{/@var{regexp}/} is an abbreviation for the following comparison expression: @@ -11566,7 +11699,7 @@ where this is discussed in more detail. The POSIX standard says that string comparison is performed based on the locale's @dfn{collating order}. This is the order in which characters sort, as defined by the locale (for more discussion, -@pxref{Ranges and Locales}). This order is usually very different +@pxref{Locales}). This order is usually very different from the results obtained when doing straight character-by-character comparison.@footnote{Technically, string comparison is supposed to behave the same way as if the strings are compared with the C @@ -11646,7 +11779,7 @@ no substring @samp{foo} in the record. True if at least one of @var{boolean1} or @var{boolean2} is true. For example, the following statement prints all records in the input that contain @emph{either} @samp{edu} or -@samp{li} or both: +@samp{li}: @example if ($0 ~ /edu/ || $0 ~ /li/) print @@ -11655,6 +11788,9 @@ if ($0 ~ /edu/ || $0 ~ /li/) print The subexpression @var{boolean2} is evaluated only if @var{boolean1} is false. This can make a difference when @var{boolean2} contains expressions that have side effects. +(Thus, this test never really distinguishes records that contain both +@samp{edu} and @samp{li}---as soon as @samp{edu} is matched, +the full test succeeds.) @item ! @var{boolean} True if @var{boolean} is false. For example, @@ -11664,7 +11800,7 @@ variable is not defined: @example BEGIN @{ if (! ("HOME" in ENVIRON)) - print "no home!" @} + print "no home!" @} @end example (The @code{in} operator is described in @@ -11963,7 +12099,7 @@ expression because the first @samp{$} has higher precedence than the @samp{++}; to avoid the problem the expression can be rewritten as @samp{$($0++)--}. -This table presents @command{awk}'s operators, in order of highest +This list presents @command{awk}'s operators, in order of highest to lowest precedence: @c @asis for docbook to come out right @@ -12120,8 +12256,8 @@ system about the local character set and language. The ISO C standard defines a default @code{"C"} locale, which is an environment that is typical of what many C programmers are used to. -Once upon a time, the locale setting used to affect regexp matching -(@pxref{Ranges and Locales}), but this is no longer true. +Once upon a time, the locale setting used to affect regexp matching, +but this is no longer true (@pxref{Ranges and Locales}). Locales can affect record splitting. For the normal case of @samp{RS = "\n"}, the locale is largely irrelevant. For other single-character @@ -12133,7 +12269,7 @@ character}, to find the record terminator. Locales can affect how dates and times are formatted (@pxref{Time Functions}). For example, a common way to abbreviate the date September 4, 2015 in the United States is ``9/4/15.'' In many countries in -Europe, however, it is abbreviated ``4.9.15.'' Thus, the @samp{%x} +Europe, however, it is abbreviated ``4.9.15.'' Thus, the @code{%x} specification in a @code{"US"} locale might produce @samp{9/4/15}, while in a @code{"EUROPE"} locale, it might produce @samp{4.9.15}. @@ -12175,7 +12311,8 @@ Locales can influence the conversions. @item @command{awk} provides the usual arithmetic operators (addition, subtraction, multiplication, division, modulus), and unary plus and minus. -It also provides comparison operators, boolean operators, and regexp +It also provides comparison operators, boolean operators, array membership +testing, and regexp matching operators. String concatenation is accomplished by placing two expressions next to each other; there is no explicit operator. The three-operand @samp{?:} operator provides an ``if-else'' test within @@ -12190,7 +12327,7 @@ In @command{awk}, a value is considered to be true if it is non-zero @emph{or} non-null. Otherwise, the value is false. @item -A value's type is set upon each assignment and may change over its +A variable's type is set upon each assignment and may change over its lifetime. The type determines how it behaves in comparisons (string or numeric). @@ -12222,7 +12359,7 @@ program, and occasionally the format for data read as input. As you have already seen, each @command{awk} statement consists of a pattern with an associated action. This @value{CHAPTER} describes how you build patterns and actions, what kinds of things you can do within -actions, and @command{awk}'s built-in variables. +actions, and @command{awk}'s predefined variables. The pattern-action rules and the statements available for use within actions form the core of @command{awk} programming. @@ -12237,7 +12374,7 @@ building something useful. * Action Overview:: What goes into an action. * Statements:: Describes the various control statements in detail. -* Built-in Variables:: Summarizes the built-in variables. +* Built-in Variables:: Summarizes the predefined variables. * Pattern Action Summary:: Patterns and Actions summary. @end menu @@ -12270,7 +12407,7 @@ is nonzero (if a number) or non-null (if a string). (@xref{Expression Patterns}.) @item @var{begpat}, @var{endpat} -A pair of patterns separated by a comma, specifying a range of records. +A pair of patterns separated by a comma, specifying a @dfn{range} of records. The range includes both the initial record that matches @var{begpat} and the final record that matches @var{endpat}. (@xref{Ranges}.) @@ -12360,8 +12497,8 @@ $ @kbd{awk '$1 ~ /li/ @{ print $2 @}' mail-list} @cindex regexp constants, as patterns @cindex patterns, regexp constants as A regexp constant as a pattern is also a special case of an expression -pattern. The expression @code{/li/} has the value one if @samp{li} -appears in the current input record. Thus, as a pattern, @code{/li/} +pattern. The expression @samp{/li/} has the value one if @samp{li} +appears in the current input record. Thus, as a pattern, @samp{/li/} matches any record containing @samp{li}. @cindex Boolean expressions, as patterns @@ -12543,7 +12680,7 @@ input is read. For example: @example $ @kbd{awk '} > @kbd{BEGIN @{ print "Analysis of \"li\"" @}} -> @kbd{/li/ @{ ++n @}} +> @kbd{/li/ @{ ++n @}} > @kbd{END @{ print "\"li\" appears in", n, "records." @}' mail-list} @print{} Analysis of "li" @print{} "li" appears in 4 records. @@ -12623,9 +12760,10 @@ The POSIX standard specifies that @code{NF} is available in an @code{END} rule. It contains the number of fields from the last input record. Most probably due to an oversight, the standard does not say that @code{$0} is also preserved, although logically one would think that it should be. -In fact, @command{gawk} does preserve the value of @code{$0} for use in -@code{END} rules. Be aware, however, that BWK @command{awk}, and possibly -other implementations, do not. +In fact, all of BWK @command{awk}, @command{mawk}, and @command{gawk} +preserve the value of @code{$0} for use in @code{END} rules. Be aware, +however, that some other implementations and many older versions +of Unix @command{awk} do not. The third point follows from the first two. The meaning of @samp{print} inside a @code{BEGIN} or @code{END} rule is the same as always: @@ -12720,8 +12858,8 @@ level of the @command{awk} program. @cindex @code{next} statement, @code{BEGINFILE}/@code{ENDFILE} patterns and The @code{next} statement (@pxref{Next Statement}) is not allowed inside -either a @code{BEGINFILE} or and @code{ENDFILE} rule. The @code{nextfile} -statement (@pxref{Nextfile Statement}) is allowed only inside a +either a @code{BEGINFILE} or an @code{ENDFILE} rule. The @code{nextfile} +statement is allowed only inside a @code{BEGINFILE} rule, but not inside an @code{ENDFILE} rule. @cindex @code{getline} statement, @code{BEGINFILE}/@code{ENDFILE} patterns and @@ -12785,7 +12923,7 @@ There are two ways to get the value of the shell variable into the body of the @command{awk} program. @cindex shells, quoting -The most common method is to use shell quoting to substitute +A common method is to use shell quoting to substitute the variable's value into the program inside the script. For example, consider the following program: @@ -13042,20 +13180,21 @@ If the @var{condition} is true, it executes the statement @var{body}. is not zero and not a null string.) @end ifinfo After @var{body} has been executed, -@var{condition} is tested again, and if it is still true, @var{body} is -executed again. This process repeats until the @var{condition} is no longer -true. If the @var{condition} is initially false, the body of the loop is -never executed and @command{awk} continues with the statement following +@var{condition} is tested again, and if it is still true, @var{body} +executes again. This process repeats until the @var{condition} is no longer +true. If the @var{condition} is initially false, the body of the loop +never executes and @command{awk} continues with the statement following the loop. This example prints the first three fields of each record, one per line: @example -awk '@{ - i = 1 - while (i <= 3) @{ - print $i - i++ - @} +awk ' +@{ + i = 1 + while (i <= 3) @{ + print $i + i++ + @} @}' inventory-shipped @end example @@ -13089,14 +13228,14 @@ do while (@var{condition}) @end example -Even if the @var{condition} is false at the start, the @var{body} is -executed at least once (and only once, unless executing @var{body} +Even if the @var{condition} is false at the start, the @var{body} +executes at least once (and only once, unless executing @var{body} makes @var{condition} true). Contrast this with the corresponding @code{while} statement: @example while (@var{condition}) - @var{body} + @var{body} @end example @noindent @@ -13106,11 +13245,11 @@ The following is an example of a @code{do} statement: @example @{ - i = 1 - do @{ - print $0 - i++ - @} while (i <= 10) + i = 1 + do @{ + print $0 + i++ + @} while (i <= 10) @} @end example @@ -13147,9 +13286,10 @@ compares it against the desired number of iterations. For example: @example -awk '@{ - for (i = 1; i <= 3; i++) - print $i +awk ' +@{ + for (i = 1; i <= 3; i++) + print $i @}' inventory-shipped @end example @@ -13177,7 +13317,7 @@ between 1 and 100: @example for (i = 1; i <= 100; i *= 2) - print i + print i @end example If there is nothing to be done, any of the three expressions in the @@ -13497,7 +13637,7 @@ The @code{next} statement is not allowed inside @code{BEGINFILE} and @cindex functions, user-defined, @code{next}/@code{nextfile} statements and According to the POSIX standard, the behavior is undefined if the @code{next} statement is used in a @code{BEGIN} or @code{END} rule. -@command{gawk} treats it as a syntax error. Although POSIX permits it, +@command{gawk} treats it as a syntax error. Although POSIX does not disallow it, most other @command{awk} implementations don't allow the @code{next} statement inside function bodies (@pxref{User-defined}). Just as with any other @code{next} statement, a @code{next} statement inside a function @@ -13552,7 +13692,7 @@ opened with redirections. It is not related to the main processing that @quotation NOTE For many years, @code{nextfile} was a -@command{gawk} extension. As of September, 2012, it was accepted for +common extension. In September, 2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @end quotation @@ -13561,8 +13701,8 @@ See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @cindex @code{nextfile} statement, user-defined functions and @cindex Brian Kernighan's @command{awk} @cindex @command{mawk} utility -The current version of BWK @command{awk}, and @command{mawk} (@pxref{Other -Versions}) also support @code{nextfile}. However, they don't allow the +The current version of BWK @command{awk}, and @command{mawk} +also support @code{nextfile}. However, they don't allow the @code{nextfile} statement inside function bodies (@pxref{User-defined}). @command{gawk} does; a @code{nextfile} inside a function body reads the next record and starts processing it with the first rule in the program, @@ -13594,8 +13734,8 @@ the program to stop immediately. An @code{exit} statement that is not part of a @code{BEGIN} or @code{END} rule stops the execution of any further automatic rules for the current record, skips reading any remaining input records, and executes the -@code{END} rule if there is one. -Any @code{ENDFILE} rules are also skipped; they are not executed. +@code{END} rule if there is one. @command{gawk} also skips +any @code{ENDFILE} rules; they do not execute. In such a case, if you don't want the @code{END} rule to do its job, set a variable @@ -13643,11 +13783,11 @@ results across different operating systems. @c ENDOFRANGE accs @node Built-in Variables -@section Built-in Variables +@section Predefined Variables @c STARTOFRANGE bvar -@cindex built-in variables +@cindex predefined variables @c STARTOFRANGE varb -@cindex variables, built-in +@cindex variables, predefined Most @command{awk} variables are available to use for your own purposes; they never change unless your program assigns values to @@ -13658,8 +13798,8 @@ to tell @command{awk} how to do certain things. Others are set automatically by @command{awk}, so that they carry information from the internal workings of @command{awk} to your program. -@cindex @command{gawk}, built-in variables and -This @value{SECTION} documents all of @command{gawk}'s built-in variables, +@cindex @command{gawk}, predefined variables and +This @value{SECTION} documents all of @command{gawk}'s predefined variables, most of which are also documented in the @value{CHAPTER}s describing their areas of activity. @@ -13674,7 +13814,7 @@ their areas of activity. @node User-modified @subsection Built-in Variables That Control @command{awk} @c STARTOFRANGE bvaru -@cindex built-in variables, user-modifiable +@cindex predefined variables, user-modifiable @c STARTOFRANGE nmbv @cindex user-modifiable variables @@ -13703,7 +13843,7 @@ respectively, should use binary I/O. A string value of @code{"rw"} or @code{"wr"} indicates that all files should use binary I/O. Any other string value is treated the same as @code{"rw"}, but causes @command{gawk} to generate a warning message. @code{BINMODE} is described in more -detail in @ref{PC Using}. @command{mawk} @pxref{Other Versions}), +detail in @ref{PC Using}. @command{mawk} (@pxref{Other Versions}), also supports this variable, but only using numeric values. @cindex @code{CONVFMT} variable @@ -13830,7 +13970,7 @@ printing with the @code{print} statement. It works by being passed as the first argument to the @code{sprintf()} function (@pxref{String Functions}). Its default value is @code{"%.6g"}. Earlier versions of @command{awk} -also used @code{OFMT} to specify the format for converting numbers to +used @code{OFMT} to specify the format for converting numbers to strings in general expressions; this is now done by @code{CONVFMT}. @cindex @code{sprintf()} function, @code{OFMT} variable and @@ -13911,9 +14051,9 @@ The default value of @code{TEXTDOMAIN} is @code{"messages"}. @subsection Built-in Variables That Convey Information @c STARTOFRANGE bvconi -@cindex built-in variables, conveying information +@cindex predefined variables, conveying information @c STARTOFRANGE vbconi -@cindex variables, built-in, conveying information +@cindex variables, predefined conveying information The following is an alphabetical list of variables that @command{awk} sets automatically on certain occasions in order to provide information to your program. @@ -13982,8 +14122,8 @@ successive instances of the same @value{FN} on the command line. @cindex file names, distinguishing While you can change the value of @code{ARGIND} within your @command{awk} -program, @command{gawk} automatically sets it to a new value when the -next file is opened. +program, @command{gawk} automatically sets it to a new value when it +opens the next file. @cindex @code{ENVIRON} array @cindex environment variables, in @code{ENVIRON} array @@ -14048,10 +14188,10 @@ can give @code{FILENAME} a value. @cindex @code{FNR} variable @item @code{FNR} -The current record number in the current file. @code{FNR} is -incremented each time a new record is read -(@pxref{Records}). It is reinitialized -to zero each time a new input file is started. +The current record number in the current file. @command{awk} increments +@code{FNR} each time it reads a new record (@pxref{Records}). +@command{awk} resets @code{FNR} to zero each time it starts a new +input file. @cindex @code{NF} variable @item @code{NF} @@ -14083,7 +14223,7 @@ array causes a fatal error. Any attempt to assign to an element of The number of input records @command{awk} has processed since the beginning of the program's execution (@pxref{Records}). -@code{NR} is incremented each time a new record is read. +@command{awk} increments @code{NR} each time it reads a new record. @cindex @command{gawk}, @code{PROCINFO} array in @cindex @code{PROCINFO} array @@ -14163,7 +14303,7 @@ The parent process ID of the current process. @item PROCINFO["sorted_in"] If this element exists in @code{PROCINFO}, its value controls the order in which array indices will be processed by -@samp{for (@var{index} in @var{array})} loops. +@samp{for (@var{indx} in @var{array})} loops. Since this is an advanced feature, we defer the full description until later; see @ref{Scanning an Array}. @@ -14184,7 +14324,7 @@ The version of @command{gawk}. The following additional elements in the array are available to provide information about the MPFR and GMP libraries -if your version of @command{gawk} supports arbitrary precision numbers +if your version of @command{gawk} supports arbitrary precision arithmetic (@pxref{Arbitrary Precision Arithmetic}): @table @code @@ -14233,14 +14373,14 @@ The @code{PROCINFO} array has the following additional uses: @itemize @value{BULLET} @item -It may be used to cause coprocesses to communicate over pseudo-ttys -instead of through two-way pipes; this is discussed further in -@ref{Two-way I/O}. - -@item It may be used to provide a timeout when reading from any open input file, pipe, or coprocess. @xref{Read Timeout}, for more information. + +@item +It may be used to cause coprocesses to communicate over pseudo-ttys +instead of through two-way pipes; this is discussed further in +@ref{Two-way I/O}. @end itemize @cindex @code{RLENGTH} variable @@ -14271,9 +14411,13 @@ the record separator. It is set every time a record is read. @cindex @code{SYMTAB} array @cindex differences in @command{awk} and @command{gawk}, @code{SYMTAB} variable @item @code{SYMTAB #} -An array whose indices are the names of all currently defined -global variables and arrays in the program. The array may be used -for indirect access to read or write the value of a variable: +An array whose indices are the names of all defined global variables and +arrays in the program. @code{SYMTAB} makes @command{gawk}'s symbol table +visible to the @command{awk} programmer. It is built as @command{gawk} +parses the program and is complete before the program starts to run. + +The array may be used for indirect access to read or write the value of +a variable: @example foo = 5 @@ -14482,6 +14626,12 @@ following @option{-v} are passed on to the @command{awk} program. (@xref{Getopt Function}, for an @command{awk} library function that parses command-line options.) +When designing your program, you should choose options that don't +conflict with @command{gawk}'s, since it will process any options +that it accepts before passing the rest of the command line on to +your program. Using @samp{#!} with the @option{-E} option may help +(@pxref{Executable Scripts}, and @pxref{Options}). + @node Pattern Action Summary @section Summary @@ -14516,7 +14666,7 @@ input and output statements, and deletion statements. The control statements in @command{awk} are @code{if}-@code{else}, @code{while}, @code{for}, and @code{do}-@code{while}. @command{gawk} adds the @code{switch} statement. There are two flavors of @code{for} -statement: one for for performing general looping, and the other iterating +statement: one for performing general looping, and the other for iterating through an array. @item @@ -14533,12 +14683,17 @@ The @code{exit} statement terminates your program. When executed from an action (or function body) it transfers control to the @code{END} statements. From an @code{END} statement body, it exits immediately. You may pass an optional numeric value to be used -at @command{awk}'s exit status. +as @command{awk}'s exit status. @item -Some built-in variables provide control over @command{awk}, mainly for I/O. +Some predefined variables provide control over @command{awk}, mainly for I/O. Other variables convey information from @command{awk} to your program. +@item +@code{ARGC} and @code{ARGV} make the command-line arguments available +to your program. Manipulating them from a @code{BEGIN} rule lets you +control how @command{awk} will process the provided @value{DF}s. + @end itemize @node Arrays @@ -14559,24 +14714,13 @@ The @value{CHAPTER} moves on to discuss @command{gawk}'s facility for sorting arrays, and ends with a brief description of @command{gawk}'s ability to support true arrays of arrays. -@cindex variables, names of -@cindex functions, names of -@cindex arrays, names of, and names of functions/variables -@cindex names, arrays/variables -@cindex namespace issues -@command{awk} maintains a single set -of names that may be used for naming variables, arrays, and functions -(@pxref{User-defined}). -Thus, you cannot have a variable and an array with the same name in the -same @command{awk} program. - @menu * Array Basics:: The basics of arrays. -* Delete:: The @code{delete} statement removes an element - from an array. * Numeric Array Subscripts:: How to use numbers as subscripts in @command{awk}. * Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The @code{delete} statement removes an element + from an array. * Multidimensional:: Emulating multidimensional arrays in @command{awk}. * Arrays of Arrays:: True multidimensional arrays. @@ -14622,7 +14766,7 @@ as a variable) in the same @command{awk} program. Arrays in @command{awk} superficially resemble arrays in other programming languages, but there are fundamental differences. In @command{awk}, it isn't necessary to specify the size of an array before starting to use it. -Additionally, any number or string in @command{awk}, not just consecutive integers, +Additionally, any number or string, not just consecutive integers, may be used as an array index. In most other languages, arrays must be @dfn{declared} before use, @@ -15004,14 +15148,14 @@ begin with a number: @example @c file eg/misc/arraymax.awk @{ - if ($1 > max) - max = $1 - arr[$1] = $0 + if ($1 > max) + max = $1 + arr[$1] = $0 @} END @{ - for (x = 1; x <= max; x++) - print arr[x] + for (x = 1; x <= max; x++) + print arr[x] @} @c endfile @end example @@ -15051,9 +15195,9 @@ program's @code{END} rule, as follows: @example END @{ - for (x = 1; x <= max; x++) - if (x in arr) - print arr[x] + for (x = 1; x <= max; x++) + if (x in arr) + print arr[x] @} @end example @@ -15075,7 +15219,7 @@ an array: @example for (@var{var} in @var{array}) - @var{body} + @var{body} @end example @noindent @@ -15148,7 +15292,7 @@ BEGIN @{ @} @end example -Here is what happens when run with @command{gawk}: +Here is what happens when run with @command{gawk} (and @command{mawk}): @example $ @kbd{gawk -f loopcheck.awk} @@ -15266,7 +15410,8 @@ does not affect the loop. For example: @example -$ @kbd{gawk 'BEGIN @{} +$ @kbd{gawk '} +> @kbd{BEGIN @{} > @kbd{ a[4] = 4} > @kbd{ a[3] = 3} > @kbd{ for (i in a)} @@ -15274,7 +15419,8 @@ $ @kbd{gawk 'BEGIN @{} > @kbd{@}'} @print{} 4 4 @print{} 3 3 -$ @kbd{gawk 'BEGIN @{} +$ @kbd{gawk '} +> @kbd{BEGIN @{} > @kbd{ PROCINFO["sorted_in"] = "@@ind_str_asc"} > @kbd{ a[4] = 4} > @kbd{ a[3] = 3} @@ -15323,118 +15469,6 @@ the @code{delete} statement. In addition, @command{gawk} provides built-in functions for sorting arrays; see @ref{Array Sorting Functions}. -@node Delete -@section The @code{delete} Statement -@cindex @code{delete} statement -@cindex deleting elements in arrays -@cindex arrays, elements, deleting -@cindex elements in arrays, deleting - -To remove an individual element of an array, use the @code{delete} -statement: - -@example -delete @var{array}[@var{index-expression}] -@end example - -Once an array element has been deleted, any value the element once -had is no longer available. It is as if the element had never -been referred to or been given a value. -The following is an example of deleting elements in an array: - -@example -for (i in frequencies) - delete frequencies[i] -@end example - -@noindent -This example removes all the elements from the array @code{frequencies}. -Once an element is deleted, a subsequent @code{for} statement to scan the array -does not report that element and the @code{in} operator to check for -the presence of that element returns zero (i.e., false): - -@example -delete foo[4] -if (4 in foo) - print "This will never be printed" -@end example - -@cindex null strings, and deleting array elements -It is important to note that deleting an element is @emph{not} the -same as assigning it a null value (the empty string, @code{""}). -For example: - -@example -foo[4] = "" -if (4 in foo) - print "This is printed, even though foo[4] is empty" -@end example - -@cindex lint checking, array elements -It is not an error to delete an element that does not exist. -However, if @option{--lint} is provided on the command line -(@pxref{Options}), -@command{gawk} issues a warning message when an element that -is not in the array is deleted. - -@cindex common extensions, @code{delete} to delete entire arrays -@cindex extensions, common@comma{} @code{delete} to delete entire arrays -@cindex arrays, deleting entire contents -@cindex deleting entire arrays -@cindex @code{delete} @var{array} -@cindex differences in @command{awk} and @command{gawk}, array elements, deleting -All the elements of an array may be deleted with a single statement -by leaving off the subscript in the @code{delete} statement, -as follows: - - -@example -delete @var{array} -@end example - -Using this version of the @code{delete} statement is about three times -more efficient than the equivalent loop that deletes each element one -at a time. - -@cindex Brian Kernighan's @command{awk} -@quotation NOTE -For many years, -using @code{delete} without a subscript was a @command{gawk} extension. -As of September, 2012, it was accepted for -inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, -the Austin Group website}. This form of the @code{delete} statement is also supported -by BWK @command{awk} and @command{mawk}, as well as -by a number of other implementations (@pxref{Other Versions}). -@end quotation - -@cindex portability, deleting array elements -@cindex Brennan, Michael -The following statement provides a portable but nonobvious way to clear -out an array:@footnote{Thanks to Michael Brennan for pointing this out.} - -@example -split("", array) -@end example - -@cindex @code{split()} function, array elements@comma{} deleting -The @code{split()} function -(@pxref{String Functions}) -clears out the target array first. This call asks it to split -apart the null string. Because there is no data to split out, the -function simply clears the array and then returns. - -@quotation CAUTION -Deleting an array does not change its type; you cannot -delete an array and then use the array's name as a scalar -(i.e., a regular variable). For example, the following does not work: - -@example -a[1] = 3 -delete a -a = 3 -@end example -@end quotation - @node Numeric Array Subscripts @section Using Numbers to Subscript Arrays @@ -15446,7 +15480,7 @@ An important aspect to remember about arrays is that @emph{array subscripts are always strings}. When a numeric value is used as a subscript, it is converted to a string value before being used for subscripting (@pxref{Conversion}). -This means that the value of the built-in variable @code{CONVFMT} can +This means that the value of the predefined variable @code{CONVFMT} can affect how your program accesses elements of an array. For example: @example @@ -15475,7 +15509,7 @@ since @code{"12.15"} is different from @code{"12.153"}. @cindex integer array indices According to the rules for conversions (@pxref{Conversion}), integer -values are always converted to strings as integers, no matter what the +values always convert to strings as integers, no matter what the value of @code{CONVFMT} may happen to be. So the usual case of the following works: @@ -15498,7 +15532,7 @@ and all refer to the same element! As with many things in @command{awk}, the majority of the time -things work as one would expect them to. But it is useful to have a precise +things work as you would expect them to. But it is useful to have a precise knowledge of the actual rules since they can sometimes have a subtle effect on your programs. @@ -15562,6 +15596,119 @@ Even though it is somewhat unusual, the null string if @option{--lint} is provided on the command line (@pxref{Options}). +@node Delete +@section The @code{delete} Statement +@cindex @code{delete} statement +@cindex deleting elements in arrays +@cindex arrays, elements, deleting +@cindex elements in arrays, deleting + +To remove an individual element of an array, use the @code{delete} +statement: + +@example +delete @var{array}[@var{index-expression}] +@end example + +Once an array element has been deleted, any value the element once +had is no longer available. It is as if the element had never +been referred to or been given a value. +The following is an example of deleting elements in an array: + +@example +for (i in frequencies) + delete frequencies[i] +@end example + +@noindent +This example removes all the elements from the array @code{frequencies}. +Once an element is deleted, a subsequent @code{for} statement to scan the array +does not report that element and the @code{in} operator to check for +the presence of that element returns zero (i.e., false): + +@example +delete foo[4] +if (4 in foo) + print "This will never be printed" +@end example + +@cindex null strings, and deleting array elements +It is important to note that deleting an element is @emph{not} the +same as assigning it a null value (the empty string, @code{""}). +For example: + +@example +foo[4] = "" +if (4 in foo) + print "This is printed, even though foo[4] is empty" +@end example + +@cindex lint checking, array elements +It is not an error to delete an element that does not exist. +However, if @option{--lint} is provided on the command line +(@pxref{Options}), +@command{gawk} issues a warning message when an element that +is not in the array is deleted. + +@cindex common extensions, @code{delete} to delete entire arrays +@cindex extensions, common@comma{} @code{delete} to delete entire arrays +@cindex arrays, deleting entire contents +@cindex deleting entire arrays +@cindex @code{delete} @var{array} +@cindex differences in @command{awk} and @command{gawk}, array elements, deleting +All the elements of an array may be deleted with a single statement +by leaving off the subscript in the @code{delete} statement, +as follows: + + +@example +delete @var{array} +@end example + +Using this version of the @code{delete} statement is about three times +more efficient than the equivalent loop that deletes each element one +at a time. + +This form of the @code{delete} statement is also supported +by BWK @command{awk} and @command{mawk}, as well as +by a number of other implementations. + +@cindex Brian Kernighan's @command{awk} +@quotation NOTE +For many years, using @code{delete} without a subscript was a common +extension. In September, 2012, it was accepted for inclusion into the +POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, +the Austin Group website}. +@end quotation + +@cindex portability, deleting array elements +@cindex Brennan, Michael +The following statement provides a portable but nonobvious way to clear +out an array:@footnote{Thanks to Michael Brennan for pointing this out.} + +@example +split("", array) +@end example + +@cindex @code{split()} function, array elements@comma{} deleting +The @code{split()} function +(@pxref{String Functions}) +clears out the target array first. This call asks it to split +apart the null string. Because there is no data to split out, the +function simply clears the array and then returns. + +@quotation CAUTION +Deleting all the elements from an array does not change its type; you cannot +clear an array and then use the array's name as a scalar +(i.e., a regular variable). For example, the following does not work: + +@example +a[1] = 3 +delete a +a = 3 +@end example +@end quotation + @node Multidimensional @section Multidimensional Arrays @@ -15573,7 +15720,7 @@ on the command line (@pxref{Options}). @cindex arrays, multidimensional A multidimensional array is an array in which an element is identified by a sequence of indices instead of a single index. For example, a -two-dimensional array requires two indices. The usual way (in most +two-dimensional array requires two indices. The usual way (in many languages, including @command{awk}) to refer to an element of a two-dimensional array named @code{grid} is with @code{grid[@var{x},@var{y}]}. @@ -15748,8 +15895,9 @@ a[1][3][1, "name"] = "barney" Each subarray and the main array can be of different length. In fact, the elements of an array or its subarray do not all have to have the same type. This means that the main array and any of its subarrays can be -non-rectangular, or jagged in structure. One can assign a scalar value to -the index @code{4} of the main array @code{a}: +non-rectangular, or jagged in structure. You can assign a scalar value to +the index @code{4} of the main array @code{a}, even though @code{a[1]} +is itself an array and not a scalar: @example a[4] = "An element in a jagged array" @@ -15831,6 +15979,8 @@ for (i in array) @{ print array[i][j] @} @} + else + print array[i] @} @end example @@ -16115,8 +16265,9 @@ Often random integers are needed instead. Following is a user-defined function that can be used to obtain a random non-negative integer less than @var{n}: @example -function randint(n) @{ - return int(n * rand()) +function randint(n) +@{ + return int(n * rand()) @} @end example @@ -16136,8 +16287,7 @@ function roll(n) @{ return 1 + int(rand() * n) @} # Roll 3 six-sided dice and # print total number of points. @{ - printf("%d points\n", - roll(6)+roll(6)+roll(6)) + printf("%d points\n", roll(6) + roll(6) + roll(6)) @} @end example @@ -16226,7 +16376,7 @@ doing index calculations, particularly if you are used to C. In the following list, optional parameters are enclosed in square brackets@w{ ([ ]).} Several functions perform string substitution; the full discussion is provided in the description of the @code{sub()} function, which comes -towards the end since the list is presented in alphabetic order. +towards the end since the list is presented alphabetically. Those functions that are specific to @command{gawk} are marked with a pound sign (@samp{#}). They are not available in compatibility mode @@ -16270,6 +16420,7 @@ When comparing strings, @code{IGNORECASE} affects the sorting (@pxref{Array Sorting Functions}). If the @var{source} array contains subarrays as values (@pxref{Arrays of Arrays}), they will come last, after all scalar values. +Subarrays are @emph{not} recursively sorted. For example, if the contents of @code{a} are as follows: @@ -16406,7 +16557,11 @@ $ @kbd{awk 'BEGIN @{ print index("peanut", "an") @}'} @noindent If @var{find} is not found, @code{index()} returns zero. -It is a fatal error to use a regexp constant for @var{find}. +@cindex dark corner, regexp as second argument to @code{index()} +With BWK @command{awk} and @command{gawk}, +it is a fatal error to use a regexp constant for @var{find}. +Other implementations allow it, simply treating the regexp +constant as an expression meaning @samp{$0 ~ /regexp/}. @value{DARKCORNER}. @item @code{length(}[@var{string}]@code{)} @cindexawkfunc{length} @@ -16510,8 +16665,8 @@ for @code{match()}, the order is the same as for the @samp{~} operator: @cindex @code{RSTART} variable, @code{match()} function and @cindex @code{RLENGTH} variable, @code{match()} function and @cindex @code{match()} function, @code{RSTART}/@code{RLENGTH} variables -The @code{match()} function sets the built-in variable @code{RSTART} to -the index. It also sets the built-in variable @code{RLENGTH} to the +The @code{match()} function sets the predefined variable @code{RSTART} to +the index. It also sets the predefined variable @code{RLENGTH} to the length in characters of the matched substring. If no match is found, @code{RSTART} is set to zero, and @code{RLENGTH} to @minus{}1. @@ -16520,13 +16675,12 @@ For example: @example @c file eg/misc/findpat.awk @{ - if ($1 == "FIND") - regex = $2 - else @{ - where = match($0, regex) - if (where != 0) - print "Match of", regex, "found at", - where, "in", $0 + if ($1 == "FIND") + regex = $2 + else @{ + where = match($0, regex) + if (where != 0) + print "Match of", regex, "found at", where, "in", $0 @} @} @c endfile @@ -16622,7 +16776,7 @@ Any leading separator will be in @code{@var{seps}[0]}. The @code{patsplit()} function splits strings into pieces in a manner similar to the way input lines are split into fields using @code{FPAT} -(@pxref{Splitting By Content}. +(@pxref{Splitting By Content}). Before splitting the string, @code{patsplit()} deletes any previously existing elements in the arrays @var{array} and @var{seps}. @@ -16635,8 +16789,7 @@ and store the pieces in @var{array} and the separator strings in the @code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so forth. The string value of the third argument, @var{fieldsep}, is a regexp describing where to split @var{string} (much as @code{FS} can -be a regexp describing where to split input records; -@pxref{Regexp Field Splitting}). +be a regexp describing where to split input records). If @var{fieldsep} is omitted, the value of @code{FS} is used. @code{split()} returns the number of elements created. @var{seps} is a @command{gawk} extension with @code{@var{seps}[@var{i}]} @@ -16931,6 +17084,26 @@ Nonalphabetic characters are left unchanged. For example, @code{toupper("MiXeD cAsE 123")} returns @code{"MIXED CASE 123"}. @end table +@sidebar Matching the Null String +@cindex matching, null strings +@cindex null strings, matching +@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching +@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching + +In @command{awk}, the @samp{*} operator can match the null string. +This is particularly important for the @code{sub()}, @code{gsub()}, +and @code{gensub()} functions. For example: + +@example +$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} +@print{} XaXbXcX +@end example + +@noindent +Although this makes a certain amount of sense, it can be surprising. +@end sidebar + + @node Gory Details @subsubsection More About @samp{\} and @samp{&} with @code{sub()}, @code{gsub()}, and @code{gensub()} @@ -16944,7 +17117,7 @@ Nonalphabetic characters are left unchanged. For example, @cindex ampersand (@code{&}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @quotation CAUTION -This section has been known to cause headaches. +This subsubsection has been reported to cause headaches. You might want to skip it upon first reading. @end quotation @@ -17235,25 +17408,6 @@ and the special cases for @code{sub()} and @code{gsub()}, we recommend the use of @command{gawk} and @code{gensub()} when you have to do substitutions. -@sidebar Matching the Null String -@cindex matching, null strings -@cindex null strings, matching -@cindex @code{*} (asterisk), @code{*} operator, null strings@comma{} matching -@cindex asterisk (@code{*}), @code{*} operator, null strings@comma{} matching - -In @command{awk}, the @samp{*} operator can match the null string. -This is particularly important for the @code{sub()}, @code{gsub()}, -and @code{gensub()} functions. For example: - -@example -$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'} -@print{} XaXbXcX -@end example - -@noindent -Although this makes a certain amount of sense, it can be surprising. -@end sidebar - @node I/O Functions @subsection Input/Output Functions @cindex input/output functions @@ -17306,10 +17460,9 @@ buffers its output and the @code{fflush()} function forces @cindex extensions, common@comma{} @code{fflush()} function @cindex Brian Kernighan's @command{awk} -@code{fflush()} was added to BWK @command{awk} in -April of 1992. For two decades, it was not part of the POSIX standard. -As of December, 2012, it was accepted for inclusion into the POSIX -standard. +Brian Kernighan added @code{fflush()} to his @command{awk} in April +of 1992. For two decades, it was a common extension. In December, +2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=634, the Austin Group website}. POSIX standardizes @code{fflush()} as follows: If there @@ -17578,7 +17731,7 @@ is out of range, @code{mktime()} returns @minus{}1. @cindex @command{gawk}, @code{PROCINFO} array in @cindex @code{PROCINFO} array -@item @code{strftime(} [@var{format} [@code{,} @var{timestamp} [@code{,} @var{utc-flag}] ] ]@code{)} +@item @code{strftime(}[@var{format} [@code{,} @var{timestamp} [@code{,} @var{utc-flag}] ] ]@code{)} @c STARTOFRANGE strf @cindexgawkfunc{strftime} @cindex format time string @@ -17684,7 +17837,7 @@ of its ISO week number is 2013, even though its year is 2012. The full year of the ISO week number, as a decimal number. @item %h -Equivalent to @samp{%b}. +Equivalent to @code{%b}. @item %H The hour (24-hour clock) as a decimal number (00--23). @@ -17753,7 +17906,7 @@ The locale's ``appropriate'' date representation. @item %X The locale's ``appropriate'' time representation. -(This is @samp{%T} in the @code{"C"} locale.) +(This is @code{%T} in the @code{"C"} locale.) @item %y The year modulo 100 as a decimal number (00--99). @@ -17774,7 +17927,7 @@ no time zone is determinable. @item %Ec %EC %Ex %EX %Ey %EY %Od %Oe %OH @itemx %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy ``Alternate representations'' for the specifications -that use only the second letter (@samp{%c}, @samp{%C}, +that use only the second letter (@code{%c}, @code{%C}, and so on).@footnote{If you don't understand any of this, don't worry about it; these facilities are meant to make it easier to ``internationalize'' programs. @@ -17845,7 +17998,7 @@ the string. For example: @example $ date '+Today is %A, %B %d, %Y.' -@print{} Today is Monday, May 05, 2014. +@print{} Today is Monday, September 22, 2014. @end example Here is the @command{gawk} version of the @command{date} utility. @@ -18037,19 +18190,18 @@ For example, if you have a bit string @samp{10111001} and you shift it right by three bits, you end up with @samp{00010111}.@footnote{This example shows that 0's come in on the left side. For @command{gawk}, this is always true, but in some languages, it's possible to have the left side -fill with 1's. Caveat emptor.} +fill with 1's.} @c Purposely decided to use 0's and 1's here. 2/2001. -If you start over -again with @samp{10111001} and shift it left by three bits, you end up -with @samp{11001000}. -@command{gawk} provides built-in functions that implement the -bitwise operations just described. They are: +If you start over again with @samp{10111001} and shift it left by three +bits, you end up with @samp{11001000}. The following list describes +@command{gawk}'s built-in functions that implement the bitwise operations. +Optional parameters are enclosed in square brackets ([ ]): @cindex @command{gawk}, bitwise operations in @table @code @cindexgawkfunc{and} @cindex bitwise AND -@item @code{and(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{and(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise AND of the arguments. There must be at least two. @cindexgawkfunc{compl} @@ -18064,7 +18216,7 @@ Return the value of @var{val}, shifted left by @var{count} bits. @cindexgawkfunc{or} @cindex bitwise OR -@item @code{or(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{or(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise OR of the arguments. There must be at least two. @cindexgawkfunc{rshift} @@ -18074,7 +18226,7 @@ Return the value of @var{val}, shifted right by @var{count} bits. @cindexgawkfunc{xor} @cindex bitwise XOR -@item @code{xor(@var{v1}, @var{v2}} [@code{,} @dots{}]@code{)} +@item @code{xor(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} Return the bitwise XOR of the arguments. There must be at least two. @end table @@ -18197,7 +18349,7 @@ results of the @code{compl()}, @code{lshift()}, and @code{rshift()} functions. @command{gawk} provides a single function that lets you distinguish an array from a scalar variable. This is necessary for writing code -that traverses every element of an array of arrays. +that traverses every element of an array of arrays (@pxref{Arrays of Arrays}). @table @code @@ -18213,12 +18365,14 @@ an array or not. The second is inside the body of a user-defined function (not discussed yet; @pxref{User-defined}), to test if a parameter is an array or not. -Note, however, that using @code{isarray()} at the global level to test +@quotation NOTE +Using @code{isarray()} at the global level to test variables makes no sense. Since you are the one writing the program, you are supposed to know if your variables are arrays or not. And in fact, due to the way @command{gawk} works, if you pass the name of a variable that has not been previously used to @code{isarray()}, @command{gawk} -will end up turning it into a scalar. +ends up turning it into a scalar. +@end quotation @node I18N Functions @subsection String-Translation Functions @@ -18340,7 +18494,7 @@ the call. A function cannot have two parameters with the same name, nor may it have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters -cannot have the same name as one of the special built-in variables +cannot have the same name as one of the special predefined variables (@pxref{Built-in Variables}). Not all versions of @command{awk} enforce this restriction. @@ -18479,7 +18633,7 @@ extra whitespace signifies the start of the local variable list): function delarray(a, i) @{ for (i in a) - delete a[i] + delete a[i] @} @end example @@ -18490,7 +18644,7 @@ Instead of having to repeat this loop everywhere that you need to clear out an array, your program can just call @code{delarray}. (This guarantees portability. The use of @samp{delete @var{array}} to delete -the contents of an entire array is a recent@footnote{Late in 2012.} +the contents of an entire array is a relatively recent@footnote{Late in 2012.} addition to the POSIX standard.) The following is an example of a recursive function. It takes a string @@ -18520,7 +18674,7 @@ $ @kbd{echo "Don't Panic!" |} @print{} !cinaP t'noD @end example -The C @code{ctime()} function takes a timestamp and returns it in a string, +The C @code{ctime()} function takes a timestamp and returns it as a string, formatted in a well-known fashion. The following example uses the built-in @code{strftime()} function (@pxref{Time Functions}) @@ -18535,13 +18689,19 @@ to create an @command{awk} version of @code{ctime()}: function ctime(ts, format) @{ - format = PROCINFO["strftime"] + format = "%a %b %e %H:%M:%S %Z %Y" + if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) @} @c endfile @end example + +You might think that @code{ctime()} could use @code{PROCINFO["strftime"]} +for its format string. That would be a mistake, since @code{ctime()} is +supposed to return the time formatted in a standard fashion, and user-level +code could have changed @code{PROCINFO["strftime"]}. @c ENDOFRANGE fdef @node Function Caveats @@ -19113,7 +19273,7 @@ saving it in @code{start}. The last part of the code loops through each function name (from @code{$2} up to the marker, @samp{data:}), calling the function named by the field. The indirect function call itself occurs as a parameter in the call to @code{printf}. -(The @code{printf} format string uses @samp{%s} as the format specifier so that we +(The @code{printf} format string uses @code{%s} as the format specifier so that we can use functions that return strings, as well as numbers. Note that the result from the indirect call is concatenated with the empty string, in order to force it to be a string value.) @@ -19190,7 +19350,7 @@ function quicksort(data, left, right, less_than, i, last) # quicksort_swap --- helper function for quicksort, should really be inline -function quicksort_swap(data, i, j, temp) +function quicksort_swap(data, i, j, temp) @{ temp = data[i] data[i] = data[j] @@ -19311,6 +19471,69 @@ $ @kbd{gawk -f quicksort.awk -f indirectcall.awk class_data2} @print{} rsort: <100.0 95.6 93.4 87.1> @end example +Another example where indirect functions calls are useful can be found in +processing arrays. @DBREF{Walking Arrays} presented a simple function +for ``walking'' an array of arrays. That function simply printed the +name and value of each scalar array element. However, it is easy to +generalize that function, by passing in the name of a function to call +when walking an array. The modified function looks like this: + +@example +@c file eg/lib/processarray.awk +function process_array(arr, name, process, do_arrays, i, new_name) +@{ + for (i in arr) @{ + new_name = (name "[" i "]") + if (isarray(arr[i])) @{ + if (do_arrays) + @@process(new_name, arr[i]) + process_array(arr[i], new_name, process, do_arrays) + @} else + @@process(new_name, arr[i]) + @} +@} +@c endfile +@end example + +The arguments are as follows: + +@table @code +@item arr +The array. + +@item name +The name of the array (a string). + +@item process +The name of the function to call. + +@item do_arrays +If this is true, the function can handle elements that are subarrays. +@end table + +If subarrays are to be processed, that is done before walking them further. + +When run with the following scaffolding, the function produces the same +results as does the earlier @code{walk_array()} function: + +@example +BEGIN @{ + a[1] = 1 + a[2][1] = 21 + a[2][2] = 22 + a[3] = 3 + a[4][1][1] = 411 + a[4][2] = 42 + + process_array(a, "a", "do_print", 0) +@} + +function do_print(name, element) +@{ + printf "%s = %s\n", name, element +@} +@end example + Remember that you must supply a leading @samp{@@} in front of an indirect function call. Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function @@ -19341,10 +19564,11 @@ functions. @item POSIX @command{awk} provides three kinds of built-in functions: numeric, -string, and I/O. @command{gawk} provides functions that work with values -representing time, do bit manipulation, sort arrays, and internationalize -and localize programs. @command{gawk} also provides several extensions to -some of standard functions, typically in the form of additional arguments. +string, and I/O. @command{gawk} provides functions that sort arrays, work +with values representing time, do bit manipulation, determine variable +type (array vs.@: scalar), and internationalize and localize programs. +@command{gawk} also provides several extensions to some of standard +functions, typically in the form of additional arguments. @item Functions accept zero or more arguments and return a value. The @@ -19581,7 +19805,7 @@ example, @code{getopt()}'s @code{Opterr} and @code{Optind} variables (@pxref{Getopt Function}). The leading capital letter indicates that it is global, while the fact that the variable name is not all capital letters indicates that the variable is -not one of @command{awk}'s built-in variables, such as @code{FS}. +not one of @command{awk}'s predefined variables, such as @code{FS}. @cindex @option{--dump-variables} option, using for library functions It is also important that @emph{all} variables in library @@ -19595,8 +19819,9 @@ are very difficult to track down: function lib_func(x, y, l1, l2) @{ @dots{} - @var{use variable} some_var # some_var should be local - @dots{} # but is not by oversight + # some_var should be local but by oversight is not + @var{use variable} some_var + @dots{} @} @end example @@ -19637,6 +19862,7 @@ programming use. * Join Function:: A function to join an array into a string. * Getlocaltime Function:: A function to get formatted times. * Readfile Function:: A function to read an entire file at once. +* Shell Quoting:: A function to quote strings for the shell. @end menu @node Strtonum Function @@ -19707,7 +19933,7 @@ function mystrtonum(str, ret, n, i, k, c) # a[5] = "123.45" # a[6] = "1.e3" # a[7] = "1.32" -# a[7] = "1.32E2" +# a[8] = "1.32E2" # # for (i = 1; i in a; i++) # print a[i], strtonum(a[i]), mystrtonum(a[i]) @@ -19718,9 +19944,12 @@ function mystrtonum(str, ret, n, i, k, c) The function first looks for C-style octal numbers (base 8). If the input string matches a regular expression describing octal numbers, then @code{mystrtonum()} loops through each character in the -string. It sets @code{k} to the index in @code{"01234567"} of the current -octal digit. Since the return value is one-based, the @samp{k--} -adjusts @code{k} so it can be used in computing the return value. +string. It sets @code{k} to the index in @code{"1234567"} of the current +octal digit. +The return value will either be the same number as the digit, or zero +if the character is not there, which will be true for a @samp{0}. +This is safe, since the regexp test in the @code{if} ensures that +only octal values are converted. Similar logic applies to the code that checks for and converts a hexadecimal value, which starts with @samp{0x} or @samp{0X}. @@ -19753,7 +19982,7 @@ that a condition or set of conditions is true. Before proceeding with a particular computation, you make a statement about what you believe to be the case. Such a statement is known as an @dfn{assertion}. The C language provides an @code{<assert.h>} header file -and corresponding @code{assert()} macro that the programmer can use to make +and corresponding @code{assert()} macro that a programmer can use to make assertions. If an assertion fails, the @code{assert()} macro arranges to print a diagnostic message describing the condition that should have been true but was not, and then it kills the program. In C, using @@ -20223,7 +20452,7 @@ function getlocaltime(time, ret, now, i) now = systime() # return date(1)-style output - ret = strftime(PROCINFO["strftime"], now) + ret = strftime("%a %b %e %H:%M:%S %Z %Y", now) # clear out target array delete time @@ -20338,6 +20567,87 @@ if (length(contents) == 0) This tests the result to see if it is empty or not. An equivalent test would be @samp{contents == ""}. +@xref{Extension Sample Readfile}, for an extension function that +also reads an entire file into memory. + +@node Shell Quoting +@subsection Quoting Strings to Pass to The Shell + +@c included by permission +@ignore +Date: Sun, 27 Jul 2014 17:16:16 -0700 +Message-ID: <CAKuGj+iCF_obaCLDUX60aSAgbfocFVtguG39GyeoNxTFby5sqQ@mail.gmail.com> +Subject: Useful awk function +From: Mike Brennan <mike@madronabluff.com> +To: Arnold Robbins <arnold@skeeve.com> +@end ignore + +Michael Brennan offers the following programming pattern, +which he uses frequently: + +@example +#! /bin/sh + +awkp=' + @dots{} + ' + +@var{input_program} | awk "$awkp" | /bin/sh +@end example + +For example, a program of his named @command{flac-edit} has this form: + +@example +$ @kbd{flac-edit -song="Whoope! That's Great" file.flac} +@end example + +It generates the following output, which is to be piped to +the shell (@file{/bin/sh}): + +@example +chmod +w file.flac +metaflac --remove-tag=TITLE file.flac +LANG=en_US.88591 metaflac --set-tag=TITLE='Whoope! That'"'"'s Great' file.flac +chmod -w file.flac +@end example + +Note the need for shell quoting. The function @code{shell_quote()} +does it. @code{SINGLE} is the one-character string @code{"'"} and +@code{QSINGLE} is the three-character string @code{"\"'\""}. + +@example +@c file eg/lib/shellquote.awk +# shell_quote --- quote an argument for passing to the shell +@c endfile +@ignore +@c file eg/lib/shellquote.awk +# +# Michael Brennan +# brennan@@madronabluff.com +# September 2014 +@c endfile +@end ignore +@c file eg/lib/shellquote.awk + +function shell_quote(s, # parameter + SINGLE, QSINGLE, i, X, n, ret) # locals +@{ + if (s == "") + return "\"\"" + + SINGLE = "\x27" # single quote + QSINGLE = "\"\x27\"" + n = split(s, X, SINGLE) + + ret = SINGLE X[1] SINGLE + for (i = 2; i <= n; i++) + ret = ret QSINGLE SINGLE X[i] SINGLE + + return ret +@} +@c endfile +@end example + @node Data File Management @section @value{DDF} Management @@ -20395,15 +20705,14 @@ Besides solving the problem in only nine(!) lines of code, it does so @c # Arnold Robbins, arnold@@skeeve.com, Public Domain @c # January 1992 -FILENAME != _oldfilename \ -@{ +FILENAME != _oldfilename @{ if (_oldfilename != "") endfile(_oldfilename) _oldfilename = FILENAME beginfile(FILENAME) @} -END @{ endfile(FILENAME) @} +END @{ endfile(FILENAME) @} @end example This file must be loaded before the user's ``main'' program, so that the @@ -20456,7 +20765,7 @@ FNR == 1 @{ beginfile(FILENAME) @} -END @{ endfile(_filename_) @} +END @{ endfile(_filename_) @} @c endfile @end example @@ -20526,24 +20835,12 @@ function rewind( i) @c endfile @end example -This code relies on the @code{ARGIND} variable -(@pxref{Auto-set}), -which is specific to @command{gawk}. -If you are not using -@command{gawk}, you can use ideas presented in -@ifnotinfo -the previous @value{SECTION} -@end ifnotinfo -@ifinfo -@ref{Filetrans Function}, -@end ifinfo -to either update @code{ARGIND} on your own -or modify this code as appropriate. - -The @code{rewind()} function also relies on the @code{nextfile} keyword -(@pxref{Nextfile Statement}). Because of this, you should not call it -from an @code{ENDFILE} rule. (This isn't necessary anyway, since as soon -as an @code{ENDFILE} rule finishes @command{gawk} goes to the next file!) +The @code{rewind()} function relies on the @code{ARGIND} variable +(@pxref{Auto-set}), which is specific to @command{gawk}. It also +relies on the @code{nextfile} keyword (@pxref{Nextfile Statement}). +Because of this, you should not call it from an @code{ENDFILE} rule. +(This isn't necessary anyway, since as soon as an @code{ENDFILE} rule +finishes @command{gawk} goes to the next file!) @node File Checking @subsection Checking for Readable @value{DDF}s @@ -20576,7 +20873,7 @@ the following program to your @command{awk} program: BEGIN @{ for (i = 1; i < ARGC; i++) @{ - if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/ \ + if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \ || ARGV[i] == "-" || ARGV[i] == "/dev/stdin") continue # assignment or standard input else if ((getline junk < ARGV[i]) < 0) # unreadable @@ -20594,6 +20891,11 @@ Removing the element from @code{ARGV} with @code{delete} skips the file (since it's no longer in the list). See also @ref{ARGC and ARGV}. +The regular expression check purposely does not use character classes +such as @samp{[:alpha:]} and @samp{[:alnum:]} +(@pxref{Bracket Expressions}) +since @command{awk} variable names only allow the English letters. + @node Empty Files @subsection Checking for Zero-length Files @@ -20690,7 +20992,7 @@ a library file does the trick: function disable_assigns(argc, argv, i) @{ for (i = 1; i < argc; i++) - if (argv[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/) + if (argv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/) argv[i] = ("./" argv[i]) @} @@ -21062,12 +21364,18 @@ In both runs, the first @option{--} terminates the arguments to etc., as its own options. @quotation NOTE -After @code{getopt()} is through, it is the responsibility of the -user level code to clear out all the elements of @code{ARGV} from 1 +After @code{getopt()} is through, +user level code must clear out all the elements of @code{ARGV} from 1 to @code{Optind}, so that @command{awk} does not try to process the command-line options as @value{FN}s. @end quotation +Using @samp{#!} with the @option{-E} option may help avoid +conflicts between your program's options and @command{gawk}'s options, +since @option{-E} causes @command{gawk} to abandon processing of +further options +(@pxref{Executable Scripts}, and @pxref{Options}). + Several of the sample programs presented in @ref{Sample Programs}, use @code{getopt()} to process their arguments. @@ -21312,13 +21620,14 @@ The @code{BEGIN} rule sets a private variable to the directory where routine, we have chosen to put it in @file{/usr/local/libexec/awk}; however, you might want it to be in a different directory on your system. -The function @code{_pw_init()} keeps three copies of the user information -in three associative arrays. The arrays are indexed by username +The function @code{_pw_init()} fills three copies of the user information +into three associative arrays. The arrays are indexed by username (@code{_pw_byname}), by user ID number (@code{_pw_byuid}), and by order of occurrence (@code{_pw_bycount}). The variable @code{_pw_inited} is used for efficiency, since @code{_pw_init()} needs to be called only once. +@cindex @code{PROCINFO} array, testing the field splitting @cindex @code{getline} command, @code{_pw_init()} function Because this function uses @code{getline} to read information from @command{pwcat}, it first saves the values of @code{FS}, @code{RS}, and @code{$0}. @@ -21326,13 +21635,8 @@ It notes in the variable @code{using_fw} whether field splitting with @code{FIELDWIDTHS} is in effect or not. Doing so is necessary, since these functions could be called from anywhere within a user's program, and the user may have his -or her -own way of splitting records and fields. - -@cindex @code{PROCINFO} array, testing the field splitting -The @code{using_fw} variable checks @code{PROCINFO["FS"]}, which -is @code{"FIELDWIDTHS"} if field splitting is being done with -@code{FIELDWIDTHS}. This makes it possible to restore the correct +or her own way of splitting records and fields. +This makes it possible to restore the correct field-splitting mechanism later. The test can only be true for @command{gawk}. It is false if using @code{FS} or @code{FPAT}, or on some other @command{awk} implementation. @@ -21646,8 +21950,7 @@ function _gr_init( oldfs, oldrs, olddol0, grcat, n = split($4, a, "[ \t]*,[ \t]*") for (i = 1; i <= n; i++) if (a[i] in _gr_groupsbyuser) - _gr_groupsbyuser[a[i]] = \ - _gr_groupsbyuser[a[i]] " " $1 + _gr_groupsbyuser[a[i]] = gr_groupsbyuser[a[i]] " " $1 else _gr_groupsbyuser[a[i]] = $1 @@ -21855,12 +22158,12 @@ When run, the program produces the following output: @example $ @kbd{gawk -f walk_array.awk} -@print{} a[4][1][1] = 411 -@print{} a[4][2] = 42 @print{} a[1] = 1 @print{} a[2][1] = 21 @print{} a[2][2] = 22 @print{} a[3] = 3 +@print{} a[4][1][1] = 411 +@print{} a[4][2] = 42 @end example @c ENDOFRANGE libfgdata @@ -21874,8 +22177,8 @@ $ @kbd{gawk -f walk_array.awk} @itemize @value{BULLET} @item Reading programs is an excellent way to learn Good Programming. -The functions provided in this @value{CHAPTER} and the next are intended -to serve that purpose. +The functions and programs provided in this @value{CHAPTER} and the next +are intended to serve that purpose. @item When writing general-purpose library functions, put some thought into how @@ -22162,22 +22465,16 @@ supplied: # Requires getopt() and join() library functions @group -function usage( e1, e2) +function usage() @{ - e1 = "usage: cut [-f list] [-d c] [-s] [files...]" - e2 = "usage: cut [-c list] [files...]" - print e1 > "/dev/stderr" - print e2 > "/dev/stderr" + print("usage: cut [-f list] [-d c] [-s] [files...]") > "/dev/stderr" + print("usage: cut [-c list] [files...]") > "/dev/stderr" exit 1 @} @end group @c endfile @end example -@noindent -The variables @code{e1} and @code{e2} are used so that the function -fits nicely on the @value{PAGE}. - @cindex @code{BEGIN} pattern, running @command{awk} programs and @cindex @code{FS} variable, running @command{awk} programs and Next comes a @code{BEGIN} rule that parses the command-line options. @@ -22472,7 +22769,7 @@ and the file transition library program The program begins with a descriptive comment and then a @code{BEGIN} rule that processes the command-line arguments with @code{getopt()}. The @option{-i} (ignore case) option is particularly easy with @command{gawk}; we just use the -@code{IGNORECASE} built-in variable +@code{IGNORECASE} predefined variable (@pxref{Built-in Variables}): @cindex @code{egrep.awk} program @@ -22678,19 +22975,15 @@ and then exits: @example @c file eg/prog/egrep.awk -function usage( e) +function usage() @{ - e = "Usage: egrep [-csvil] [-e pat] [files ...]" - e = e "\n\tegrep [-csvil] pat [files ...]" - print e > "/dev/stderr" + print("Usage: egrep [-csvil] [-e pat] [files ...]") > "/dev/stderr" + print("\n\tegrep [-csvil] pat [files ...]") > "/dev/stderr" exit 1 @} @c endfile @end example -The variable @code{e} is used so that the function fits nicely -on the printed page. - @c ENDOFRANGE regexps @c ENDOFRANGE sfregexp @c ENDOFRANGE fsregexp @@ -22748,6 +23041,7 @@ numbers: # May 1993 # Revised February 1996 # Revised May 2014 +# Revised September 2014 @c endfile @end ignore @@ -22766,26 +23060,22 @@ BEGIN @{ printf("uid=%d", uid) pw = getpwuid(uid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (euid != uid) @{ printf(" euid=%d", euid) pw = getpwuid(euid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) @} printf(" gid=%d", gid) pw = getgrgid(gid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (egid != gid) @{ printf(" egid=%d", egid) pw = getgrgid(egid) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) @} for (i = 1; ("group" i) in PROCINFO; i++) @{ @@ -22794,8 +23084,7 @@ BEGIN @{ group = PROCINFO["group" i] printf("%d", group) pw = getgrgid(group) - if (pw != "") - pr_first_field(pw) + pr_first_field(pw) if (("group" (i+1)) in PROCINFO) printf(",") @} @@ -22805,8 +23094,10 @@ BEGIN @{ function pr_first_field(str, a) @{ - split(str, a, ":") - printf("(%s)", a[1]) + if (str != "") @{ + split(str, a, ":") + printf("(%s)", a[1]) + @} @} @c endfile @end example @@ -22829,7 +23120,8 @@ tested, and the loop body never executes. The @code{pr_first_field()} function simply isolates out some code that is used repeatedly, making the whole program -slightly shorter and cleaner. +shorter and cleaner. In particular, moving the check for +the empty string into this function saves several lines of code. @c ENDOFRANGE id @@ -22956,19 +23248,14 @@ The @code{usage()} function simply prints an error message and exits: @example @c file eg/prog/split.awk -function usage( e) +function usage() @{ - e = "usage: split [-num] [file] [outname]" - print e > "/dev/stderr" + print("usage: split [-num] [file] [outname]") > "/dev/stderr" exit 1 @} @c endfile @end example -@noindent -The variable @code{e} is used so that the function -fits nicely on the @value{PAGE}. - This program is a bit sloppy; it relies on @command{awk} to automatically close the last file instead of doing it in an @code{END} rule. It also assumes that letters are contiguous in the character set, @@ -23127,10 +23414,10 @@ The options for @command{uniq} are: @table @code @item -d -Print only repeated lines. +Print only repeated (duplicated) lines. @item -u -Print only nonrepeated lines. +Print only nonrepeated (unique) lines. @item -c Count lines. This option overrides @option{-d} and @option{-u}. Both repeated @@ -23199,10 +23486,9 @@ standard output, @file{/dev/stdout}: @end ignore @c file eg/prog/uniq.awk -function usage( e) +function usage() @{ - e = "Usage: uniq [-udc [-n]] [+n] [ in [ out ]]" - print e > "/dev/stderr" + print("Usage: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr" exit 1 @} @@ -23256,22 +23542,20 @@ BEGIN @{ @end example The following function, @code{are_equal()}, compares the current line, -@code{$0}, to the -previous line, @code{last}. It handles skipping fields and characters. -If no field count and no character count are specified, @code{are_equal()} -simply returns one or zero depending upon the result of a simple string -comparison of @code{last} and @code{$0}. Otherwise, things get more -complicated. -If fields have to be skipped, each line is broken into an array using -@code{split()} -(@pxref{String Functions}); -the desired fields are then joined back into a line using @code{join()}. -The joined lines are stored in @code{clast} and @code{cline}. -If no fields are skipped, @code{clast} and @code{cline} are set to -@code{last} and @code{$0}, respectively. -Finally, if characters are skipped, @code{substr()} is used to strip off the -leading @code{charcount} characters in @code{clast} and @code{cline}. The -two strings are then compared and @code{are_equal()} returns the result: +@code{$0}, to the previous line, @code{last}. It handles skipping fields +and characters. If no field count and no character count are specified, +@code{are_equal()} returns one or zero depending upon the result of a +simple string comparison of @code{last} and @code{$0}. + +Otherwise, things get more complicated. If fields have to be skipped, +each line is broken into an array using @code{split()} (@pxref{String +Functions}); the desired fields are then joined back into a line +using @code{join()}. The joined lines are stored in @code{clast} and +@code{cline}. If no fields are skipped, @code{clast} and @code{cline} +are set to @code{last} and @code{$0}, respectively. Finally, if +characters are skipped, @code{substr()} is used to strip off the leading +@code{charcount} characters in @code{clast} and @code{cline}. The two +strings are then compared and @code{are_equal()} returns the result: @example @c file eg/prog/uniq.awk @@ -23362,6 +23646,13 @@ END @{ @c endfile @end example +@c FIXME: Include this? +@ignore +This program does not follow our recommended convention of naming +global variables with a leading capital letter. Doing that would +make the program a little easier to follow. +@end ignore + @ifset FOR_PRINT The logic for choosing which lines to print represents a @dfn{state machine}, which is ``a device that can be in one of a set number of stable @@ -23369,7 +23660,7 @@ conditions depending on its previous condition and on the present values of its inputs.''@footnote{This is the definition returned from entering @code{define: state machine} into Google.} Brian Kernighan suggests that -``an alternative approach to state mechines is to just read +``an alternative approach to state machines is to just read the input into an array, then use indexing. It's almost always easier code, and for most inputs where you would use this, just as fast.'' Consider how to rewrite the logic to follow this @@ -23407,7 +23698,7 @@ one or more input files. Its usage is as follows: If no files are specified on the command line, @command{wc} reads its standard input. If there are multiple files, it also prints total counts for all -the files. The options and their meanings are shown in the following list: +the files. The options and their meanings are as follows: @table @code @item -l @@ -23888,8 +24179,8 @@ character of the ``to'' list is used for the remaining characters in the Once upon a time, @c early or mid-1989! -a user proposed that a transliteration function should -be added to @command{gawk}. +a user proposed adding a transliteration function +to @command{gawk}. @c Wishing to avoid gratuitous new features, @c at least theoretically The following program was written to @@ -23897,15 +24188,12 @@ prove that character transliteration could be done with a user-level function. This program is not as complete as the system @command{tr} utility but it does most of the job. -The @command{translate} program demonstrates one of the few weaknesses -of standard @command{awk}: dealing with individual characters is very -painful, requiring repeated use of the @code{substr()}, @code{index()}, -and @code{gsub()} built-in functions -(@pxref{String Functions}).@footnote{This -program was also written before @command{gawk} acquired the ability to -split each character in a string into separate array elements.} -There are two functions. The first, @code{stranslate()}, takes three -arguments: +The @command{translate} program was written long before @command{gawk} +acquired the ability to split each character in a string into separate +array elements. Thus, it makes repeated use of the @code{substr()}, +@code{index()}, and @code{gsub()} built-in functions (@pxref{String +Functions}). There are two functions. The first, @code{stranslate()}, +takes three arguments: @table @code @item from @@ -23924,7 +24212,7 @@ loop goes through @code{from}, one character at a time. For each character in @code{from}, if the character appears in @code{target}, it is replaced with the corresponding @code{to} character. -The @code{translate()} function simply calls @code{stranslate()} using @code{$0} +The @code{translate()} function calls @code{stranslate()} using @code{$0} as the target. The main program sets two global variables, @code{FROM} and @code{TO}, from the command line, and then changes @code{ARGV} so that @command{awk} reads from the standard input. @@ -24059,7 +24347,7 @@ of lines on the page Most of the work is done in the @code{printpage()} function. The label lines are stored sequentially in the @code{line} array. But they have to print horizontally; @code{line[1]} next to @code{line[6]}, -@code{line[2]} next to @code{line[7]}, and so on. Two loops are used to +@code{line[2]} next to @code{line[7]}, and so on. Two loops accomplish this. The outer loop, controlled by @code{i}, steps through every 10 lines of data; this is each row of labels. The inner loop, controlled by @code{j}, goes through the lines within the row. @@ -24173,7 +24461,7 @@ in a useful format. At first glance, a program like this would seem to do the job: @example -# Print list of word frequencies +# wordfreq-first-try.awk --- print list of word frequencies @{ for (i = 1; i <= NF; i++) @@ -24390,16 +24678,16 @@ Texinfo input file into separate files. This @value{DOCUMENT} is written in @uref{http://www.gnu.org/software/texinfo/, Texinfo}, the GNU project's document formatting language. A single Texinfo source file can be used to produce both -printed and online documentation. +printed documentation, with @TeX{}, and online documentation. @ifnotinfo -Texinfo is fully documented in the book +(Texinfo is fully documented in the book @cite{Texinfo---The GNU Documentation Format}, available from the Free Software Foundation, -and also available @uref{http://www.gnu.org/software/texinfo/manual/texinfo/, online}. +and also available @uref{http://www.gnu.org/software/texinfo/manual/texinfo/, online}.) @end ifnotinfo @ifinfo -The Texinfo language is described fully, starting with -@inforef{Top, , Texinfo, texinfo,Texinfo---The GNU Documentation Format}. +(The Texinfo language is described fully, starting with +@inforef{Top, , Texinfo, texinfo,Texinfo---The GNU Documentation Format}.) @end ifinfo For our purposes, it is enough to know three things about Texinfo input @@ -24477,8 +24765,7 @@ exits with a zero exit status, signifying OK: @cindex @code{extract.awk} program @example @c file eg/prog/extract.awk -# extract.awk --- extract files and run programs -# from texinfo files +# extract.awk --- extract files and run programs from texinfo files @c endfile @ignore @c file eg/prog/extract.awk @@ -24492,8 +24779,7 @@ exits with a zero exit status, signifying OK: BEGIN @{ IGNORECASE = 1 @} -/^@@c(omment)?[ \t]+system/ \ -@{ +/^@@c(omment)?[ \t]+system/ @{ if (NF < 3) @{ e = ("extract: " FILENAME ":" FNR) e = (e ": badly formed `system' line") @@ -24550,8 +24836,7 @@ line. That line is then printed to the output file: @example @c file eg/prog/extract.awk -/^@@c(omment)?[ \t]+file/ \ -@{ +/^@@c(omment)?[ \t]+file/ @{ if (NF != 3) @{ e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") print e > "/dev/stderr" @@ -24611,7 +24896,7 @@ The @code{END} rule handles the final cleanup, closing the open file: function unexpected_eof() @{ printf("extract: %s:%d: unexpected EOF or error\n", - FILENAME, FNR) > "/dev/stderr" + FILENAME, FNR) > "/dev/stderr" exit 1 @} @end group @@ -24639,7 +24924,7 @@ While @command{sed} is a complicated program in its own right, its most common use is to perform global substitutions in the middle of a pipeline: @example -command1 < orig.data | sed 's/old/new/g' | command2 > result +@var{command1} < orig.data | sed 's/old/new/g' | @var{command2} > result @end example Here, @samp{s/old/new/g} tells @command{sed} to look for the regexp @@ -24871,6 +25156,7 @@ should be the @command{awk} program. If there are no command-line arguments left, @command{igawk} prints an error message and exits. Otherwise, the first argument is appended to @code{program}. In any case, after the arguments have been processed, +the shell variable @code{program} contains the complete text of the original @command{awk} program. @@ -24993,8 +25279,8 @@ the path, and an attempt is made to open the generated @value{FN}. The only way to test if a file can be read in @command{awk} is to go ahead and try to read it with @code{getline}; this is what @code{pathto()} does.@footnote{On some very old versions of @command{awk}, the test -@samp{getline junk < t} can loop forever if the file exists but is empty. -Caveat emptor.} If the file can be read, it is closed and the @value{FN} +@samp{getline junk < t} can loop forever if the file exists but is empty.} +If the file can be read, it is closed and the @value{FN} is returned: @ignore @@ -25194,12 +25480,10 @@ in C or C++, and it is frequently easier to do certain kinds of string and argument manipulation using the shell than it is in @command{awk}. Finally, @command{igawk} shows that it is not always necessary to add new -features to a program; they can often be layered on top. -@ignore -With @command{igawk}, -there is no real reason to build @code{@@include} processing into -@command{gawk} itself. -@end ignore +features to a program; they can often be layered on top.@footnote{@command{gawk} +does @code{@@include} processing itself in order to support the use +of @command{awk} programs as Web CGI scripts.} + @c ENDOFRANGE libfex @c ENDOFRANGE flibex @c ENDOFRANGE awkpex @@ -25217,12 +25501,11 @@ One word is an anagram of another if both words contain the same letters (for example, ``babbling'' and ``blabbing''). -An elegant algorithm is presented in Column 2, Problem C of -Jon Bentley's @cite{Programming Pearls}, second edition. -The idea is to give words that are anagrams a common signature, -sort all the words together by their signature, and then print them. -Dr.@: Bentley observes that taking the letters in each word and -sorting them produces that common signature. +Column 2, Problem C of Jon Bentley's @cite{Programming Pearls}, second +edition, presents an elegant algorithm. The idea is to give words that +are anagrams a common signature, sort all the words together by their +signature, and then print them. Dr.@: Bentley observes that taking the +letters in each word and sorting them produces that common signature. The following program uses arrays of arrays to bring together words with the same signature and array sorting to print the words @@ -25456,7 +25739,7 @@ BEGIN { @itemize @value{BULLET} @item -The functions provided in this @value{CHAPTER} and the previous one +The programs provided in this @value{CHAPTER} continue on the theme that reading programs is an excellent way to learn Good Programming. @@ -25494,7 +25777,7 @@ mailing labels, and finding anagrams. @enumerate @item Rewrite @file{cut.awk} (@pxref{Cut Program}) -using @code{split()} with @code{""} as the seperator. +using @code{split()} with @code{""} as the separator. @item In @ref{Egrep Program}, we mentioned that @samp{egrep -i} could be @@ -25526,7 +25809,7 @@ conditions depending on its previous condition and on the present values of its inputs.''@footnote{This is the definition returned from entering @code{define: state machine} into Google.} Brian Kernighan suggests that -``an alternative approach to state mechines is to just read +``an alternative approach to state machines is to just read the input into an array, then use indexing. It's almost always easier code, and for most inputs where you would use this, just as fast.'' Rewrite the logic to follow this @@ -25733,13 +26016,11 @@ discusses the ability to dynamically add new built-in functions to @cindex constants, nondecimal If you run @command{gawk} with the @option{--non-decimal-data} option, -you can have nondecimal constants in your input data: +you can have nondecimal values in your input data: -@c line break here for small book format @example $ @kbd{echo 0123 123 0x123 |} -> @kbd{gawk --non-decimal-data '@{ printf "%d, %d, %d\n",} -> @kbd{$1, $2, $3 @}'} +> @kbd{gawk --non-decimal-data '@{ printf "%d, %d, %d\n", $1, $2, $3 @}'} @print{} 83, 123, 291 @end example @@ -25780,6 +26061,8 @@ Instead, use the @code{strtonum()} function to convert your data (@pxref{String Functions}). This makes your programs easier to write and easier to read, and leads to less surprising results. + +This option may disappear in a future version of @command{gawk}. @end quotation @node Array Sorting @@ -25814,7 +26097,9 @@ pre-defined values to @code{PROCINFO["sorted_in"]} in order to control the order in which @command{gawk} traverses an array during a @code{for} loop. -In addition, the value of @code{PROCINFO["sorted_in"]} can be a function name. +In addition, the value of @code{PROCINFO["sorted_in"]} can be a +function name.@footnote{This is why the predefined sorting orders +start with an @samp{@@} character, which cannot be part of an identifier.} This lets you traverse an array based on any custom criterion. The array elements are ordered according to the return value of this function. The comparison function should be defined with at least @@ -25946,7 +26231,7 @@ according to login name. The following program sorts records by a specific field position and can be used for this purpose: @example -# sort.awk --- simple program to sort by field position +# passwd-sort.awk --- simple program to sort by field position # field position is specified by the global variable POS function cmp_field(i1, v1, i2, v2) @@ -26005,7 +26290,7 @@ As mentioned above, the order of the indices is arbitrary if two elements compare equal. This is usually not a problem, but letting the tied elements come out in arbitrary order can be an issue, especially when comparing item values. The partial ordering of the equal elements -may change during the next loop traversal, if other elements are added or +may change the next time the array is traversed, if other elements are added or removed from the array. One way to resolve ties when comparing elements with otherwise equal values is to include the indices in the comparison rules. Note that doing this may make the loop traversal less efficient, @@ -26174,7 +26459,6 @@ come into play; comparisons are based on character values only.@footnote{This is true because locale-based comparison occurs only when in POSIX compatibility mode, and since @code{asort()} and @code{asorti()} are @command{gawk} extensions, they are not available in that case.} -Caveat Emptor. @node Two-way I/O @section Two-Way Communications with Another Process @@ -26240,7 +26524,7 @@ for example, @file{/tmp} will not do, as another user might happen to be using a temporary file with the same name.@footnote{Michael Brennan suggests the use of @command{rand()} to generate unique @value{FN}s. This is a valid point; nevertheless, temporary files -remain more difficult than two-way pipes.} @c 8/2014 +remain more difficult to use than two-way pipes.} @c 8/2014 @cindex coprocesses @cindex input/output, two-way @@ -26379,21 +26663,23 @@ using regular pipes. @cindex @code{EMISTERED} @ifnotdocbook @quotation -@code{EMISTERED}:@* +@code{EMRED}:@* @ @ @ @ @i{A host is a host from coast to coast,@* -@ @ @ @ and no-one can talk to host that's close,@* +@ @ @ @ and nobody talks to a host that's close,@* @ @ @ @ unless the host that isn't close@* -@ @ @ @ is busy hung or dead.} +@ @ @ @ is busy, hung, or dead.} +@author Mike O'Brien (aka Mr.@: Protocol) @end quotation @end ifnotdocbook @docbook <blockquote> +<attribution>Mike O'Brien (aka Mr. Protocol)</attribution> <literallayout class="normal"><literal>EMISTERED</literal>: <emphasis>A host is a host from coast to coast,</emphasis> <emphasis>and no-one can talk to host that's close,</emphasis> <emphasis>unless the host that isn't close</emphasis> - <emphasis>is busy hung or dead.</emphasis></literallayout> + <emphasis>is busy, hung, or dead.</emphasis></literallayout> </blockquote> @end docbook @@ -26424,7 +26710,7 @@ the system default, most likely IPv4. @item protocol The protocol to use over IP. This must be either @samp{tcp}, or @samp{udp}, for a TCP or UDP IP connection, -respectively. The use of TCP is recommended for most applications. +respectively. TCP should be used for most applications. @item local-port @cindex @code{getaddrinfo()} function (C library) @@ -26457,10 +26743,10 @@ Consider the following very simple example: @example BEGIN @{ - Service = "/inet/tcp/0/localhost/daytime" - Service |& getline - print $0 - close(Service) + Service = "/inet/tcp/0/localhost/daytime" + Service |& getline + print $0 + close(Service) @} @end example @@ -26563,9 +26849,9 @@ in the morning to work.) @cindex @code{BEGIN} pattern, and profiling @cindex @code{END} pattern, and profiling @example - # gawk profile, created Thu Feb 27 05:16:21 2014 + # gawk profile, created Mon Sep 29 05:16:21 2014 - # BEGIN block(s) + # BEGIN rule(s) BEGIN @{ 1 print "First BEGIN rule" @@ -26592,7 +26878,7 @@ in the morning to work.) @} @} - # END block(s) + # END rule(s) END @{ 1 print "First END rule" @@ -26702,8 +26988,7 @@ The profiled version of your program may not look exactly like what you typed when you wrote it. This is because @command{gawk} creates the profiled version by ``pretty printing'' its internal representation of the program. The advantage to this is that @command{gawk} can produce -a standard representation. The disadvantage is that all source-code -comments are lost. +a standard representation. Also, things such as: @example @@ -26720,7 +27005,7 @@ come out as: @end example @noindent -which is correct, but possibly surprising. +which is correct, but possibly unexpected. @cindex profiling @command{awk} programs, dynamically @cindex @command{gawk} program, dynamic profiling @@ -26752,7 +27037,7 @@ $ @kbd{kill -USR1 13992} @noindent As usual, the profiled version of the program is written to -@file{awkprof.out}, or to a different file if one specified with +@file{awkprof.out}, or to a different file if one was specified with the @option{--profile} option. Along with the regular profile, as shown earlier, the profile file @@ -26800,6 +27085,23 @@ When called this way, @command{gawk} ``pretty prints'' the program into Once upon a time, the @option{--pretty-print} option would also run your program. This is is no longer the case. @end quotation + +There is a significant difference between the output created when +profiling, and that created when pretty-printing. Pretty-printed output +preserves the original comments that were in the program, although their +placement may not correspond exactly to their original locations in the +source code. + +However, as a deliberate design decision, profiling output @emph{omits} +the original program's comments. This allows you to focus on the +execution count data and helps you avoid the temptation to use the +profiler for pretty-printing. + +Additionally, pretty-printed output does not have the leading indentation +that the profiling output does. This makes it easy to pretty-print your +code once development is completed, and then use the result as the final +version of your program. + @c ENDOFRANGE awkp @c ENDOFRANGE proawk @@ -26812,6 +27114,7 @@ The @option{--non-decimal-data} option causes @command{gawk} to treat octal- and hexadecimal-looking input data as octal and hexadecimal. This option should be used with caution or not at all; use of @code{strtonum()} is preferable. +Note that this option may disappear in a future version of @command{gawk}. @item You can take over complete control of sorting in @samp{for (@var{indx} in @var{array})} @@ -26825,15 +27128,15 @@ those functions sort arrays. Or you may provide one of the predefined control strings that work for @code{PROCINFO["sorted_in"]}. @item -You can use the @samp{|&} operator to create a two-way pipe to a co-process. -You read from the co-process with @code{getline} and write to it with @code{print} -or @code{printf}. Use @code{close()} to close off the co-process completely, or +You can use the @samp{|&} operator to create a two-way pipe to a coprocess. +You read from the coprocess with @code{getline} and write to it with @code{print} +or @code{printf}. Use @code{close()} to close off the coprocess completely, or optionally, close off one side of the two-way communications. @item -By using special ``@value{FN}s'' with the @samp{|&} operator, you can open a +By using special @value{FN}s with the @samp{|&} operator, you can open a TCP/IP (or UDP/IP) connection to remote hosts in the Internet. @command{gawk} -supports both IPv4 an IPv6. +supports both IPv4 and IPv6. @item You can generate statement count profiles of your program. This can help you @@ -27071,7 +27374,7 @@ In June 2001 Bruno Haible wrote: This information is accessed via the POSIX character classes in regular expressions, such as @code{/[[:alnum:]]/} -(@pxref{Regexp Operators}). +(@pxref{Bracket Expressions}). @cindex monetary information, localization @cindex currency symbols, localization @@ -27154,7 +27457,7 @@ default arguments. Return the plural form used for @var{number} of the translation of @var{string1} and @var{string2} in text domain @var{domain} for locale category @var{category}. @var{string1} is the -English singular variant of a message, and @var{string2} the English plural +English singular variant of a message, and @var{string2} is the English plural variant of the same message. The default value for @var{domain} is the current value of @code{TEXTDOMAIN}. The default value for @var{category} is @code{"LC_MESSAGES"}. @@ -27242,9 +27545,11 @@ This example would be better done with @code{dcngettext()}: @example if (groggy) - message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") + message = dcngettext("%d customer disturbing me\n", + "%d customers disturbing me\n", "adminprog") else - message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") + message = dcngettext("enjoying %d customer\n", + "enjoying %d customers\n", "adminprog") printf(message, ncustomers) @end example @@ -27316,7 +27621,7 @@ First, use the @option{--gen-pot} command-line option to create the initial @file{.pot} file: @example -$ @kbd{gawk --gen-pot -f guide.awk > guide.pot} +gawk --gen-pot -f guide.awk > guide.pot @end example @cindex @code{xgettext} utility @@ -27380,11 +27685,11 @@ example, @samp{string} is the first argument and @samp{length(string)} is the se @example $ @kbd{gawk 'BEGIN @{} -> @kbd{string = "Dont Panic"} +> @kbd{string = "Don\47t Panic"} > @kbd{printf "%2$d characters live in \"%1$s\"\n",} > @kbd{string, length(string)} > @kbd{@}'} -@print{} 10 characters live in "Dont Panic" +@print{} 11 characters live in "Don't Panic" @end example If present, positional specifiers come first in the format specification, @@ -27596,7 +27901,8 @@ msgstr "Like, the scoop is" @cindex GNU/Linux The next step is to make the directory to hold the binary message object file and then to create the @file{guide.mo} file. -We pretend that our file is to be used in the @code{en_US.UTF-8} locale. +We pretend that our file is to be used in the @code{en_US.UTF-8} locale, +since we have to use a locale name known to the C @command{gettext} routines. The directory layout shown here is standard for GNU @command{gettext} on GNU/Linux systems. Other versions of @command{gettext} may use a different layout: @@ -27617,8 +27923,8 @@ $ @kbd{mkdir en_US.UTF-8 en_US.UTF-8/LC_MESSAGES} The @command{msgfmt} utility does the conversion from human-readable @file{.po} file to machine-readable @file{.mo} file. By default, @command{msgfmt} creates a file named @file{messages}. -This file must be renamed and placed in the proper directory so that -@command{gawk} can find it: +This file must be renamed and placed in the proper directory (using +the @option{-o} option) so that @command{gawk} can find it: @example $ @kbd{msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo} @@ -27661,8 +27967,8 @@ complete detail in @cite{GNU gettext tools}}.) @end ifnotinfo As of this writing, the latest version of GNU @command{gettext} is -@uref{ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.1.tar.gz, -@value{PVERSION} 0.19.1}. +@uref{ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.3.tar.gz, +@value{PVERSION} 0.19.3}. If a translation of @command{gawk}'s messages exists, then @command{gawk} produces usage messages, warnings, @@ -27750,7 +28056,7 @@ the discussion of debugging in @command{gawk}. @subsection Debugging in General (If you have used debuggers in other languages, you may want to skip -ahead to the next section on the specific features of the @command{awk} +ahead to the next section on the specific features of the @command{gawk} debugger.) Of course, a debugging program cannot remove bugs for you, since it has @@ -27790,7 +28096,7 @@ is going wrong (or, for that matter, to better comprehend a perfectly functional program that you or someone else wrote). @node Debugging Terms -@subsection Additional Debugging Concepts +@subsection Debugging Concepts Before diving in to the details, we need to introduce several important concepts that apply to just about all debuggers. @@ -27879,8 +28185,8 @@ as our example. @cindex starting the debugger @cindex debugger, how to start -Starting the debugger is almost exactly like running @command{gawk}, -except you have to pass an additional option @option{--debug} or the +Starting the debugger is almost exactly like running @command{gawk} normally, +except you have to pass an additional option @option{--debug}, or the corresponding short option @option{-D}. The file(s) containing the program and any supporting code are given on the command line as arguments to one or more @option{-f} options. (@command{gawk} is not designed @@ -27898,6 +28204,7 @@ this syntax is slightly different from what they are used to. With the @command{gawk} debugger, you give the arguments for running the program in the command line to the debugger rather than as part of the @code{run} command at the debugger prompt.) +The @option{-1} is an option to @file{uniq.awk}. Instead of immediately running the program on @file{inputfile}, as @command{gawk} would ordinarily do, the debugger merely loads all @@ -28079,7 +28386,7 @@ gawk> @kbd{p n m alast aline} This is kind of disappointing, though. All we found out is that there are five elements in @code{alast}; @code{m} and @code{aline} don't have -values yet since we are at line 68 but haven't executed it yet. +values since we are at line 68 but haven't executed it yet. This information is useful enough (we now know that none of the words were accidentally left out), but what if we want to see inside the array? @@ -28272,7 +28579,8 @@ Delete breakpoint(s) set at entry to function @var{function}. @cindex breakpoint condition @item @code{condition} @var{n} @code{"@var{expression}"} Add a condition to existing breakpoint or watchpoint @var{n}. The -condition is an @command{awk} expression that the debugger evaluates +condition is an @command{awk} expression @emph{enclosed in double quotes} +that the debugger evaluates whenever the breakpoint or watchpoint is reached. If the condition is true, then the debugger stops execution and prompts for a command. Otherwise, the debugger continues executing the program. If the condition expression is @@ -28460,7 +28768,7 @@ see the output shown under @code{dump} in @ref{Miscellaneous Debugger Commands}. @item @code{until} [[@var{filename}@code{:}]@var{n} | @var{function}] @itemx @code{u} [[@var{filename}@code{:}]@var{n} | @var{function}] Without any argument, continue execution until a line past the current -line in current stack frame is reached. With an argument, +line in the current stack frame is reached. With an argument, continue execution until the specified location is reached, or the current stack frame returns. @end table @@ -28524,7 +28832,7 @@ gawk> @kbd{print $3} @noindent This prints the third field in the input record (if the specified field does not exist, it prints @samp{Null field}). A variable can be an array element, with -the subscripts being constant values. To print the contents of an array, +the subscripts being constant string values. To print the contents of an array, prefix the name of the array with the @samp{@@} symbol: @example @@ -28590,7 +28898,7 @@ watch list. @end table @node Execution Stack -@subsection Dealing with the Stack +@subsection Working with the Stack Whenever you run a program which contains any function calls, @command{gawk} maintains a stack of all of the function calls leading up @@ -28601,16 +28909,22 @@ functions which called the one you are in. The commands for doing this are: @table @asis @cindex debugger commands, @code{bt} (@code{backtrace}) @cindex debugger commands, @code{backtrace} +@cindex debugger commands, @code{where} (@code{backtrace}) @cindex @code{backtrace} debugger command @cindex @code{bt} debugger command (alias for @code{backtrace}) +@cindex @code{where} debugger command +@cindex @code{where} debugger command (alias for @code{backtrace}) @cindex call stack, display in debugger @cindex traceback, display in debugger @item @code{backtrace} [@var{count}] @itemx @code{bt} [@var{count}] +@itemx @code{where} [@var{count}] Print a backtrace of all function calls (stack frames), or innermost @var{count} frames if @var{count} > 0. Print the outermost @var{count} frames if @var{count} < 0. The backtrace displays the name and arguments to each function, the source @value{FN}, and the line number. +The alias @code{where} for @code{backtrace} is provided for long-time +GDB users who may be used to that command. @cindex debugger commands, @code{down} @cindex @code{down} debugger command @@ -28660,7 +28974,7 @@ The value for @var{what} should be one of the following: @table @code @item args @cindex show function arguments, in debugger -Arguments of the selected frame. +List arguments of the selected frame. @item break @cindex show breakpoints @@ -28672,7 +28986,7 @@ List all items in the automatic display list. @item frame @cindex describe call stack frame, in debugger -Description of the selected stack frame. +Give a description of the selected stack frame. @item functions @cindex list function definitions, in debugger @@ -28681,11 +28995,11 @@ line numbers. @item locals @cindex show local variables, in debugger -Local variables of the selected frame. +List local variables of the selected frame. @item source @cindex show name of current source file, in debugger -The name of the current source file. Each time the program stops, the +Print the name of the current source file. Each time the program stops, the current source file is the file containing the current instruction. When the debugger first starts, the current source file is the first file included via the @option{-f} option. The @@ -28802,6 +29116,7 @@ commands in a program. This can be very enlightening, as the following partial dump of Davide Brini's obfuscated code (@pxref{Signature Program}) demonstrates: +@c FIXME: This will need updating if num-handler branch is ever merged in. @smallexample gawk> @kbd{dump} @print{} # BEGIN @@ -28875,7 +29190,7 @@ are as follows: @c nested table @table @asis -@item @code{-} +@item @code{-} (Minus) Print lines before the lines last printed. @item @code{+} @@ -28963,7 +29278,7 @@ and @end table @node Limitations -@section Limitations and Future Plans +@section Limitations We hope you find the @command{gawk} debugger useful and enjoyable to work with, but as with any program, especially in its early releases, it still has @@ -29011,8 +29326,10 @@ executing, short programs. The @command{gawk} debugger only accepts source supplied with the @option{-f} option. @end itemize +@ignore Look forward to a future release when these and other missing features may be added, and of course feel free to try to add them yourself! +@end ignore @node Debugging Summary @section Summary @@ -29055,9 +29372,8 @@ and editing. @cindex floating-point, numbers@comma{} arbitrary precision This @value{CHAPTER} introduces some basic concepts relating to -how computers do arithmetic and briefly lists the features in -@command{gawk} for performing arbitrary precision floating point -computations. It then proceeds to describe floating-point arithmetic, +how computers do arithmetic and defines some important terms. +It then proceeds to describe floating-point arithmetic, which is what @command{awk} uses for all its computations, including a discussion of arbitrary precision floating point arithmetic, which is a feature available only in @command{gawk}. It continues on to present @@ -29152,10 +29468,12 @@ Computers work with integer and floating point values of different ranges. Integer values are usually either 32 or 64 bits in size. Single precision floating point values occupy 32 bits, whereas double precision floating point values occupy 64 bits. Floating point values are always -signed. The possible ranges of values are shown in the following table. +signed. The possible ranges of values are shown in @ref{table-numeric-ranges}. +@float Table,table-numeric-ranges +@caption{Value Ranges for Different Numeric Representations} @multitable @columnfractions .34 .33 .33 -@headitem Numeric representation @tab Miniumum value @tab Maximum value +@headitem Numeric representation @tab Minimum value @tab Maximum value @item 32-bit signed integer @tab @minus{}2,147,483,648 @tab 2,147,483,647 @item 32-bit unsigned integer @tab 0 @tab 4,294,967,295 @item 64-bit signed integer @tab @minus{}9,223,372,036,854,775,808 @tab 9,223,372,036,854,775,807 @@ -29163,6 +29481,7 @@ signed. The possible ranges of values are shown in the following table. @item Single precision floating point (approximate) @tab @code{1.175494e-38} @tab @code{3.402823e+38} @item Double precision floating point (approximate) @tab @code{2.225074e-308} @tab @code{1.797693e+308} @end multitable +@end float @node Math Definitions @section Other Stuff To Know @@ -29190,14 +29509,12 @@ A special value representing infinity. Operations involving another number and infinity produce infinity. @item NaN -``Not A Number.''@footnote{Thanks -to Michael Brennan for this description, which I have paraphrased, and -for the examples}. -A special value that results from attempting a -calculation that has no answer as a real number. In such a case, -programs can either receive a floating-point exception, or get @code{NaN} -back as the result. The IEEE 754 standard recommends that systems return -@code{NaN}. Some examples: +``Not A Number.''@footnote{Thanks to Michael Brennan for this description, +which we have paraphrased, and for the examples.} A special value that +results from attempting a calculation that has no answer as a real number. +In such a case, programs can either receive a floating-point exception, +or get @code{NaN} back as the result. The IEEE 754 standard recommends +that systems return @code{NaN}. Some examples: @table @code @item sqrt(-1) @@ -29271,9 +29588,9 @@ to allow greater precisions and larger exponent ranges. field values for the basic IEEE 754 binary formats: @float Table,table-ieee-formats -@caption{Basic IEEE Format Context Values} +@caption{Basic IEEE Format Values} @multitable @columnfractions .20 .20 .20 .20 .20 -@headitem Name @tab Total bits @tab Precision @tab emin @tab emax +@headitem Name @tab Total bits @tab Precision @tab Minimum exponent @tab Maximum exponent @item Single @tab 32 @tab 24 @tab @minus{}126 @tab +127 @item Double @tab 64 @tab 53 @tab @minus{}1022 @tab +1023 @item Quadruple @tab 128 @tab 113 @tab @minus{}16382 @tab +16383 @@ -29286,18 +29603,18 @@ one extra bit of significand. @end quotation @node MPFR features -@section Arbitrary Precison Arithmetic Features In @command{gawk} +@section Arbitrary Precision Arithmetic Features In @command{gawk} -By default, @command{gawk} uses the double precision floating point values +By default, @command{gawk} uses the double precision floating-point values supplied by the hardware of the system it runs on. However, if it was -compiled to do, @command{gawk} uses the @uref{http://www.mpfr.org, GNU -MPFR} and @uref{http://gmplib.org, GNU MP} (GMP) libraries for arbitrary +compiled to do so, @command{gawk} uses the @uref{http://www.mpfr.org +GNU MPFR} and @uref{http://gmplib.org, GNU MP} (GMP) libraries for arbitrary precision arithmetic on numbers. You can see if MPFR support is available like so: @example $ @kbd{gawk --version} -@print{} GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) +@print{} GNU Awk 4.1.2, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2) @print{} Copyright (C) 1989, 1991-2014 Free Software Foundation. @dots{} @end example @@ -29317,11 +29634,12 @@ results. With the @option{-M} command-line option, all floating-point arithmetic operators and numeric functions can yield results to any desired precision level supported by MPFR. -Two built-in variables, @code{PREC} and @code{ROUNDMODE}, +Two predefined variables, @code{PREC} and @code{ROUNDMODE}, provide control over the working precision and the rounding mode. The precision and the rounding mode are set globally for every operation to follow. -@xref{Auto-set}, for more information. +@xref{Setting precision}, and @ref{Setting the rounding mode}, +for more information. @node FP Math Caution @section Floating Point Arithmetic: Caveat Emptor! @@ -29435,6 +29753,10 @@ else # not ok @end example +@noindent +(We assume that you have a simple absolute value function named +@code{abs()} defined elsewhere in your program.) + @node Errors accumulate @subsubsection Errors Accumulate @@ -29521,7 +29843,7 @@ It is easy to forget that the finite number of bits used to store the value is often just an approximation after proper rounding. The test for equality succeeds if and only if @emph{all} bits in the two operands are exactly the same. Since this is not necessarily true after floating-point -computations with a particular precision and effective rounding rule, +computations with a particular precision and effective rounding mode, a straight test for equality may not work. Instead, compare the two numbers to see if they are within the desirable delta of each other. @@ -29588,7 +29910,7 @@ $ @kbd{gawk -f pi2.awk} the precision or accuracy of individual numbers. Performing an arithmetic operation or calling a built-in function rounds the result to the current working precision. The default working precision is 53 bits, which you can -modify using the built-in variable @code{PREC}. You can also set the +modify using the predefined variable @code{PREC}. You can also set the value to one of the predefined case-insensitive strings shown in @ref{table-predefined-precision-strings}, to emulate an IEEE 754 binary format. @@ -29620,7 +29942,7 @@ Be wary of floating-point constants! When reading a floating-point constant from program source code, @command{gawk} uses the default precision (that of a C @code{double}), unless overridden by an assignment to the special variable @code{PREC} on the command line, to store it -internally as a MPFR number. Changing the precision using @code{PREC} +internally as an MPFR number. Changing the precision using @code{PREC} in the program text does @emph{not} change the precision of a constant. If you need to represent a floating-point constant at a higher precision @@ -29758,15 +30080,15 @@ the following computes 5<superscript>4<superscript>3<superscript>2</superscript></superscript></superscript>, @c @end docbook the result of which is beyond the -limits of ordinary hardware double-precision floating point values: +limits of ordinary hardware double precision floating point values: @example $ @kbd{gawk -M 'BEGIN @{} > @kbd{x = 5^4^3^2} -> @kbd{print "# of digits =", length(x)} +> @kbd{print "number of digits =", length(x)} > @kbd{print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)} > @kbd{@}'} -@print{} # of digits = 183231 +@print{} number of digits = 183231 @print{} 62060698786608744707 ... 92256259918212890625 @end example @@ -29868,7 +30190,7 @@ using this user-defined function: @end ignore @c file eg/lib/div.awk -function div(numerator, denominator, result, i) +function div(numerator, denominator, result) @{ split("", result) @@ -29882,6 +30204,80 @@ function div(numerator, denominator, result, i) @c endfile @end example +The following example program, contributed by Katie Wasserman, +uses @code{div()} to +compute the digits of @value{PI} to as many places as you +choose to set: + +@example +@c file eg/prog/pi.awk +# pi.awk --- compute the digits of pi +@c endfile +@c endfile +@ignore +@c file eg/prog/pi.awk +# +# Katie Wasserman, katie@@wass.net +# August 2014 +@c endfile +@end ignore +@c file eg/prog/pi.awk + +BEGIN @{ + digits = 100000 + two = 2 * 10 ^ digits + pi = two + for (m = digits * 4; m > 0; --m) @{ + d = m * 2 + 1 + x = pi * m + div(x, d, result) + pi = result["quotient"] + pi = pi + two + @} + print pi +@} +@c endfile +@end example + +@ignore +Date: Wed, 20 Aug 2014 10:19:11 -0400 +To: arnold@skeeve.com +From: Katherine Wasserman <katie@wass.net> +Subject: Re: computation of digits of pi? + +Arnold, + +>The program that you sent to compute the digits of pi using div(). Is +>that some standard algorithm that every math student knows? If so, +>what's it called? + +It's not that well known but it's not that obscure either + +It's Euler's modification to Newton's method for calculating pi. + +Take a look at lines (23) - (25) here: http://mathworld.wolfram.com/PiFormulas.htm + +The algorithm I wrote simply expands the multiply by 2 and works from the innermost expression outwards. I used this to program HP calculators because it's quite easy to modify for tiny memory devices with smallish word sizes. + +http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899 + +-Katie +@end ignore + +When asked about the algorithm used, Katie replied: + +@quotation +It's not that well known but it's not that obscure either. +It's Euler's modification to Newton's method for calculating pi. +Take a look at lines (23) - (25) here: @uref{http://mathworld.wolfram.com/PiFormulas.htm}. + +The algorithm I wrote simply expands the multiply by 2 and works from +the innermost expression outwards. I used this to program HP calculators +because it's quite easy to modify for tiny memory devices with smallish +word sizes. See +@uref{http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899}. +@end quotation + @node POSIX Floating Point Problems @section Standards Versus Existing Practice @@ -29989,7 +30385,7 @@ Thus @samp{+nan} and @samp{+NaN} are the same. @itemize @value{BULLET} @item Most computer arithmetic is done using either integers or floating-point -values. The default for @command{awk} is to use double-precision +values. Standard @command{awk} uses double precision floating-point values. @item @@ -30108,7 +30504,7 @@ Extensions are written in C or C++, using the @dfn{Application Programming Interface} (API) defined for this purpose by the @command{gawk} developers. The rest of this @value{CHAPTER} explains the facilities that the API provides and how to use -them, and presents a small sample extension. In addition, it documents +them, and presents a small example extension. In addition, it documents the sample extensions included in the @command{gawk} distribution, and describes the @code{gawkextlib} project. @ifclear FOR_PRINT @@ -30124,10 +30520,14 @@ goals and design. @node Plugin License @section Extension Licensing -Every dynamic extension should define the global symbol -@code{plugin_is_GPL_compatible} to assert that it has been licensed under -a GPL-compatible license. If this symbol does not exist, @command{gawk} -emits a fatal error and exits when it tries to load your extension. +Every dynamic extension must be distributed under a license that is +compatible with the GNU GPL (@pxref{Copying}). + +In order for the extension to tell @command{gawk} that it is +properly licensed, the extension must define the global symbol +@code{plugin_is_GPL_compatible}. If this symbol does not exist, +@command{gawk} emits a fatal error and exits when it tries to load +your extension. The declared type of the symbol should be @code{int}. It does not need to be in any allocated section, though. The code merely asserts that @@ -30142,7 +30542,7 @@ int plugin_is_GPL_compatible; Communication between @command{gawk} and an extension is two-way. First, when an extension -is loaded, it is passed a pointer to a @code{struct} whose fields are +is loaded, @command{gawk} passes it a pointer to a @code{struct} whose fields are function pointers. @ifnotdocbook This is shown in @ref{figure-load-extension}. @@ -30178,29 +30578,29 @@ This is shown in @inlineraw{docbook, <xref linkend="figure-load-extension"/>}. The extension can call functions inside @command{gawk} through these function pointers, at runtime, without needing (link-time) access to @command{gawk}'s symbols. One of these function pointers is to a -function for ``registering'' new built-in functions. +function for ``registering'' new functions. @ifnotdocbook -This is shown in @ref{figure-load-new-function}. +This is shown in @ref{figure-register-new-function}. @end ifnotdocbook @ifdocbook -This is shown in @inlineraw{docbook, <xref linkend="figure-load-new-function"/>}. +This is shown in @inlineraw{docbook, <xref linkend="figure-register-new-function"/>}. @end ifdocbook @ifnotdocbook -@float Figure,figure-load-new-function -@caption{Loading The New Function} +@float Figure,figure-register-new-function +@caption{Registering A New Function} @ifinfo -@center @image{api-figure2, , , Loading The New Function, txt} +@center @image{api-figure2, , , Registering A New Function, txt} @end ifinfo @ifnotinfo -@center @image{api-figure2, , , Loading The New Function} +@center @image{api-figure2, , , Registering A New Function} @end ifnotinfo @end float @end ifnotdocbook @docbook -<figure id="figure-load-new-function" float="0"> -<title>Loading The New Function</title> +<figure id="figure-register-new-function" float="0"> +<title>Registering A New Function</title> <mediaobject> <imageobject role="web"><imagedata fileref="api-figure2.png" format="PNG"/></imageobject> </mediaobject> @@ -30250,8 +30650,8 @@ and understandable. Although all of this sounds somewhat complicated, the result is that extension code is quite straightforward to write and to read. You can -see this in the sample extensions @file{filefuncs.c} (@pxref{Extension -Example}) and also the @file{testext.c} code for testing the APIs. +see this in the sample extension @file{filefuncs.c} (@pxref{Extension +Example}) and also in the @file{testext.c} code for testing the APIs. Some other bits and pieces: @@ -30285,13 +30685,13 @@ This (rather large) @value{SECTION} describes the API in detail. @menu * Extension API Functions Introduction:: Introduction to the API functions. * General Data Types:: The data types. -* Requesting Values:: How to get a value. * Memory Allocation Functions:: Functions for allocating memory. * Constructor Functions:: Functions for creating values. * Registration Functions:: Functions to register things with @command{gawk}. * Printing Messages:: Functions for printing messages. * Updating @code{ERRNO}:: Functions for updating @code{ERRNO}. +* Requesting Values:: How to get a value. * Accessing Parameters:: Functions for accessing parameters. * Symbol Table Access:: Functions for accessing global variables. @@ -30310,6 +30710,9 @@ API function pointers are provided for the following kinds of operations: @itemize @value{BULLET} @item +Allocating, reallocating, and releasing memory. + +@item Registration functions. You may register: @itemize @value{MINUS} @item @@ -30342,9 +30745,6 @@ Symbol table access: retrieving a global variable, creating one, or changing one. @item -Allocating, reallocating, and releasing memory. - -@item Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -30412,15 +30812,15 @@ does not support this keyword, you should either place All pointers filled in by @command{gawk} point to memory managed by @command{gawk} and should be treated by the extension as read-only. Memory for @emph{all} strings passed into @command{gawk} -from the extension @emph{must} come from calling the API-provided function -pointers @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}, +from the extension @emph{must} come from calling one of +@code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}, and is managed by @command{gawk} from then on. @item The API defines several simple @code{struct}s that map values as seen from @command{awk}. A value can be a @code{double}, a string, or an array (as in multidimensional arrays, or when creating a new array). -String values maintain both pointer and length since embedded @value{NUL} +String values maintain both pointer and length since embedded @sc{nul} characters are allowed. @quotation NOTE @@ -30433,7 +30833,7 @@ and also how characters are likely to be input and output from files. @item When retrieving a value (such as a parameter or that of a global variable or array element), the extension requests a specific type (number, string, -scalars, value cookie, array, or ``undefined''). When the request is +scalar, value cookie, array, or ``undefined''). When the request is ``undefined,'' the returned value will have the real underlying type. However, if the request and actual type don't match, the access function @@ -30496,8 +30896,8 @@ A simple boolean type. This represents a mutable string. @command{gawk} owns the memory pointed to if it supplied the value. Otherwise, it takes ownership of the memory pointed to. -@strong{Such memory must come from calling the API-provided function -pointers @code{api_malloc()}, @code{api_calloc()}, or @code{api_realloc()}!} +@strong{Such memory must come from calling one of the +@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()} functions!} As mentioned earlier, strings are maintained using the current multibyte encoding. @@ -30552,7 +30952,7 @@ Scalar values in @command{awk} are either numbers or strings. The indicates what is in the @code{union}. Representing numbers is easy---the API uses a C @code{double}. Strings -require more work. Since @command{gawk} allows embedded @value{NUL} bytes +require more work. Since @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. @@ -30592,7 +30992,7 @@ the cookie for getting the variable's value or for changing the variable's value. This is the @code{awk_scalar_t} type and @code{scalar_cookie} macro. Given a scalar cookie, @command{gawk} can directly retrieve or -modify the value, as required, without having to first find it. +modify the value, as required, without having to find it first. The @code{awk_value_cookie_t} type and @code{value_cookie} macro are similar. If you know that you wish to @@ -30602,149 +31002,6 @@ and then pass in that value cookie whenever you wish to set the value of a variable. This saves both storage space within the running @command{gawk} process as well as the time needed to create the value. -@node Requesting Values -@subsection Requesting Values - -All of the functions that return values from @command{gawk} -work in the same way. You pass in an @code{awk_valtype_t} value -to indicate what kind of value you expect. If the actual value -matches what you requested, the function returns true and fills -in the @code{awk_value_t} result. -Otherwise, the function returns false, and the @code{val_type} -member indicates the type of the actual value. You may then -print an error message, or reissue the request for the actual -value type, as appropriate. This behavior is summarized in -@ref{table-value-types-returned}. - -@c FIXME: Try to do this with spans... - -@float Table,table-value-types-returned -@caption{API Value Types Returned} -@docbook -<informaltable> -<tgroup cols="2"> - <colspec colwidth="50*"/><colspec colwidth="50*"/> - <thead> - <row><entry></entry><entry><para>Type of Actual Value:</para></entry></row> - </thead> - <tbody> - <row><entry></entry><entry></entry></row> - </tbody> -</tgroup> -<tgroup cols="6"> - <colspec colwidth="16.6*"/> - <colspec colwidth="16.6*"/> - <colspec colwidth="19.8*"/> - <colspec colwidth="15*"/> - <colspec colwidth="15*"/> - <colspec colwidth="16.6*"/> - <thead> - <row> - <entry></entry> - <entry></entry> - <entry><para>String</para></entry> - <entry><para>Number</para></entry> - <entry><para>Array</para></entry> - <entry><para>Undefined</para></entry> - </row> - </thead> - <tbody> - <row> - <entry></entry> - <entry><para><emphasis role="bold">String</emphasis></para></entry> - <entry><para>String</para></entry> - <entry><para>String</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Number</emphasis></para></entry> - <entry><para>Number if can be converted, else false</para></entry> - <entry><para>Number</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry><para><emphasis role="bold">Type</emphasis></para></entry> - <entry><para><emphasis role="bold">Array</emphasis></para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - <entry><para>Array</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry><para><emphasis role="bold">Requested:</emphasis></para></entry> - <entry><para><emphasis role="bold">Scalar</emphasis></para></entry> - <entry><para>Scalar</para></entry> - <entry><para>Scalar</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Undefined</emphasis></para></entry> - <entry><para>String</para></entry> - <entry><para>Number</para></entry> - <entry><para>Array</para></entry> - <entry><para>Undefined</para></entry> - </row> - <row> - <entry></entry> - <entry><para><emphasis role="bold">Value Cookie</emphasis></para></entry> - <entry><para>false</para></entry> - <entry><para>false</para></entry> - <entry><para>false</para> - </entry><entry><para>false</para></entry> - </row> - </tbody> -</tgroup> -</informaltable> -@end docbook - -@ifnotplaintext -@ifnotdocbook -@multitable @columnfractions .50 .50 -@headitem @tab Type of Actual Value: -@end multitable -@multitable @columnfractions .166 .166 .198 .15 .15 .166 -@headitem @tab @tab String @tab Number @tab Array @tab Undefined -@item @tab @b{String} @tab String @tab String @tab false @tab false -@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab false @tab false -@item @b{Type} @tab @b{Array} @tab false @tab false @tab Array @tab false -@item @b{Requested:} @tab @b{Scalar} @tab Scalar @tab Scalar @tab false @tab false -@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined -@item @tab @b{Value Cookie} @tab false @tab false @tab false @tab false -@end multitable -@end ifnotdocbook -@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 | | | | | -+-----------+-----------+------------+------------+-----------+-----------+ -@end example -@end ifplaintext -@end float - @node Memory Allocation Functions @subsection Memory Allocation Functions and Convenience Macros @cindex allocating memory for extensions @@ -30753,22 +31010,24 @@ value type, as appropriate. This behavior is summarized in The API provides a number of @dfn{memory allocation} functions for allocating memory that can be passed to @command{gawk}, as well as a number of convenience macros. +This @value{SUBSECTION} presents them all as function prototypes, in +the way that extension code would use them. @table @code @item void *gawk_malloc(size_t size); -Call @command{gawk}-provided @code{api_malloc()} to allocate storage that may +Call the correct version of @code{malloc()} to allocate storage that may be passed to @command{gawk}. @item void *gawk_calloc(size_t nmemb, size_t size); -Call @command{gawk}-provided @code{api_calloc()} to allocate storage that may +Call the correct version of @code{calloc()} to allocate storage that may be passed to @command{gawk}. @item void *gawk_realloc(void *ptr, size_t size); -Call @command{gawk}-provided @code{api_realloc()} to allocate storage that may +Call the correct version of @code{realloc()} to allocate storage that may be passed to @command{gawk}. @item void gawk_free(void *ptr); -Call @command{gawk}-provided @code{api_free()} to release storage that was +Call the correct version of @code{free()} to release storage that was allocated with @code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}. @end table @@ -30782,8 +31041,8 @@ unrelated version of @code{malloc()}, unexpected behavior would likely result. Two convenience macros may be used for allocating storage -from the API-provided function pointers @code{api_malloc()} and -@code{api_realloc()}. If the allocation fails, they cause @command{gawk} +from @code{gawk_malloc()} and +@code{gawk_realloc()}. If the allocation fails, they cause @command{gawk} to exit with a fatal error message. They should be used as if they were procedure calls that do not return a value. @@ -30797,7 +31056,7 @@ The arguments to this macro are as follows: The pointer variable to point at the allocated storage. @item type -The type of the pointer variable, used to create a cast for the call to @code{api_malloc()}. +The type of the pointer variable, used to create a cast for the call to @code{gawk_malloc()}. @item size The total number of bytes to be allocated. @@ -30821,8 +31080,8 @@ make_malloced_string(message, strlen(message), & result); @end example @item #define erealloc(pointer, type, size, message) @dots{} -This is like @code{emalloc()}, but it calls @code{api_realloc()}, -instead of @code{api_malloc()}. +This is like @code{emalloc()}, but it calls @code{gawk_realloc()}, +instead of @code{gawk_malloc()}. The arguments are the same as for the @code{emalloc()} macro. @end table @@ -30846,7 +31105,7 @@ for storage in @code{result}. It returns @code{result}. @itemx make_malloced_string(const char *string, size_t length, awk_value_t *result) This function creates a string value in the @code{awk_value_t} variable pointed to by @code{result}. It expects @code{string} to be a @samp{char *} -value pointing to data previously obtained from the api-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. The idea here +value pointing to data previously obtained from @code{gawk_malloc()}, @code{gawk_calloc()} or @code{gawk_realloc()}. The idea here is that the data is passed directly to @command{gawk}, which assumes responsibility for it. It returns @code{result}. @@ -30901,17 +31160,18 @@ The name of the new function. This is a regular C string. Function names must obey the rules for @command{awk} -identifiers. That is, they must begin with either a letter +identifiers. That is, they must begin with either an English letter 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); -This is a pointer to the C function that provides the desired +This is a pointer to the C function that provides the extension's functionality. -The function must fill in the result with either a number +The function must fill in @code{*result} with either a number or a string. @command{gawk} takes ownership of any string memory. -As mentioned earlier, string memory @strong{must} come from the api-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. +As mentioned earlier, string memory @strong{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. @@ -30922,7 +31182,7 @@ This is for the convenience of the calling code inside @command{gawk}. @item size_t num_expected_args; This is the 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. Following @command{awk} functions, it +arguments isn't what it expected. As with real @command{awk} functions, it is likely OK to ignore extra arguments. @end table @@ -31176,7 +31436,7 @@ If the concept of a ``record terminator'' makes sense, then @code{RT}, and @code{*rt_len} should be set to the length of the data. Otherwise, @code{*rt_len} should be set to zero. @code{gawk} makes its own copy of this data, so the -extension must manage the storage. +extension must manage this storage. @end table The return value is the length of the buffer pointed to by @@ -31455,10 +31715,148 @@ into a (possibly translated) string using the C @code{strerror()} function. Set @code{ERRNO} directly to the string value of @code{ERRNO}. @command{gawk} makes a copy of the value of @code{string}. -@item void unset_ERRNO(); +@item void unset_ERRNO(void); Unset @code{ERRNO}. @end table +@node Requesting Values +@subsection Requesting Values + +All of the functions that return values from @command{gawk} +work in the same way. You pass in an @code{awk_valtype_t} value +to indicate what kind of value you expect. If the actual value +matches what you requested, the function returns true and fills +in the @code{awk_value_t} result. +Otherwise, the function returns false, and the @code{val_type} +member indicates the type of the actual value. You may then +print an error message, or reissue the request for the actual +value type, as appropriate. This behavior is summarized in +@ref{table-value-types-returned}. + +@float Table,table-value-types-returned +@caption{API Value Types Returned} +@docbook +<informaltable> +<tgroup cols="6"> + <colspec colwidth="16.6*"/> + <colspec colwidth="16.6*"/> + <colspec colwidth="19.8*" colname="c3"/> + <colspec colwidth="15*" colname="c4"/> + <colspec colwidth="15*" colname="c5"/> + <colspec colwidth="16.6*" colname="c6"/> + <spanspec spanname="hspan" namest="c3" nameend="c6" align="center"/> + <thead> + <row><entry></entry><entry spanname="hspan"><para>Type of Actual Value:</para></entry></row> + <row> + <entry></entry> + <entry></entry> + <entry><para>String</para></entry> + <entry><para>Number</para></entry> + <entry><para>Array</para></entry> + <entry><para>Undefined</para></entry> + </row> + </thead> + <tbody> + <row> + <entry></entry> + <entry><para><emphasis role="bold">String</emphasis></para></entry> + <entry><para>String</para></entry> + <entry><para>String</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Number</emphasis></para></entry> + <entry><para>Number if can be converted, else false</para></entry> + <entry><para>Number</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry><para><emphasis role="bold">Type</emphasis></para></entry> + <entry><para><emphasis role="bold">Array</emphasis></para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + <entry><para>Array</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry><para><emphasis role="bold">Requested:</emphasis></para></entry> + <entry><para><emphasis role="bold">Scalar</emphasis></para></entry> + <entry><para>Scalar</para></entry> + <entry><para>Scalar</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Undefined</emphasis></para></entry> + <entry><para>String</para></entry> + <entry><para>Number</para></entry> + <entry><para>Array</para></entry> + <entry><para>Undefined</para></entry> + </row> + <row> + <entry></entry> + <entry><para><emphasis role="bold">Value Cookie</emphasis></para></entry> + <entry><para>false</para></entry> + <entry><para>false</para></entry> + <entry><para>false</para> + </entry><entry><para>false</para></entry> + </row> + </tbody> +</tgroup> +</informaltable> +@end docbook + +@ifnotplaintext +@ifnotdocbook +@multitable @columnfractions .50 .50 +@headitem @tab Type of Actual Value: +@end multitable +@c 10/2014: Thanks to Karl Berry for this bit to reduce the space: +@tex +\vglue-1.1\baselineskip +@end tex +@multitable @columnfractions .166 .166 .198 .15 .15 .166 +@headitem @tab @tab String @tab Number @tab Array @tab Undefined +@item @tab @b{String} @tab String @tab String @tab false @tab false +@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab false @tab false +@item @b{Type} @tab @b{Array} @tab false @tab false @tab Array @tab false +@item @b{Requested:} @tab @b{Scalar} @tab Scalar @tab Scalar @tab false @tab false +@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined +@item @tab @b{Value Cookie} @tab false @tab false @tab false @tab false +@end multitable +@end ifnotdocbook +@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 | | | | | ++-----------+-----------+------------+------------+-----------+-----------+ +@end example +@end ifplaintext +@end float + @node Accessing Parameters @subsection Accessing and Updating Parameters @@ -31513,7 +31911,7 @@ about symbols is termed a @dfn{symbol table}. Fill in the @code{awk_value_t} structure pointed to by @code{result} with the value of the variable named by the string @code{name}, which is a regular C string. @code{wanted} indicates the type of value expected. -Return true if the actual type matches @code{wanted}, false otherwise +Return true if the actual type matches @code{wanted}, false otherwise. In the latter case, @code{result->val_type} indicates the actual type (@pxref{table-value-types-returned}). @@ -31532,7 +31930,7 @@ 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 NOTE +@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 @@ -31554,14 +31952,14 @@ The following functions let you work with scalar cookies. @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted, @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result); Retrieve the current value of a scalar cookie. -Once you have obtained a scalar_cookie using @code{sym_lookup()}, you can +Once you have obtained a scalar cookie using @code{sym_lookup()}, you can use this function to get its value more efficiently. 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}. -Here too, the built-in variables may not be updated. +Here too, the predefined variables may not be updated. @end table It is not obvious at first glance how to work with scalar cookies or @@ -31616,7 +32014,7 @@ my_extension_init() /* install initial value */ sym_update("MAGIC_VAR", make_number(42.0, & value)); - /* get cookie */ + /* get the cookie */ sym_lookup("MAGIC_VAR", AWK_SCALAR, & value); /* save the cookie */ @@ -31665,7 +32063,8 @@ assign those values to variables using @code{sym_update()} or @code{sym_update_scalar()}, as you like. However, you can understand the point of cached values if you remember that -@emph{every} string value's storage @emph{must} come from @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()}. +@emph{every} string value's storage @emph{must} come from @code{gawk_malloc()}, +@code{gawk_calloc()} or @code{gawk_realloc()}. If you have 20 variables, all of which have the same string value, you must create 20 identical copies of the string.@footnote{Numeric values are clearly less problematic, requiring only a C @code{double} to store.} @@ -31736,7 +32135,7 @@ Using value cookies in this way saves considerable storage, since all of You might be wondering, ``Is this sharing problematic? What happens if @command{awk} code assigns a new value to @code{VAR1}, -are all the others be changed too?'' +are all the others changed too?'' That's a great question. The answer is that no, it's not a problem. Internally, @command{gawk} uses @dfn{reference-counted strings}. This means @@ -31791,7 +32190,7 @@ with the @code{<stdio.h>} library routines. @itemx @ @ @ @ struct awk_element *next; @itemx @ @ @ @ enum @{ @itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DEFAULT = 0,@ @ /* set by gawk */ -@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DELETE = 1@ @ @ @ /* set by extension if should be deleted */ +@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DELETE = 1@ @ @ @ /* set by extension */ @itemx @ @ @ @ @} flags; @itemx @ @ @ @ awk_value_t index; @itemx @ @ @ @ awk_value_t value; @@ -31811,8 +32210,8 @@ an extension to create a linked list of new elements that can then be added to an array in a loop that traverses the list. @item enum @{ @dots{} @} flags; -A set of flag values that convey information between @command{gawk} -and the extension. Currently there is only one: @code{AWK_ELEMENT_DELETE}. +A set of flag values that convey information between the extension +and @command{gawk}. Currently there is only one: @code{AWK_ELEMENT_DELETE}. Setting it causes @command{gawk} to delete the element from the original array upon release of the flattened array. @@ -31823,8 +32222,8 @@ The index and value of the element, respectively. @end table @item typedef struct awk_flat_array @{ -@itemx @ @ @ @ awk_const void *awk_const opaque1;@ @ @ @ /* private data for use by gawk */ -@itemx @ @ @ @ awk_const void *awk_const opaque2;@ @ @ @ /* private data for use by gawk */ +@itemx @ @ @ @ awk_const void *awk_const opaque1;@ @ @ @ /* for use by gawk */ +@itemx @ @ @ @ awk_const void *awk_const opaque2;@ @ @ @ /* for use by gawk */ @itemx @ @ @ @ awk_const size_t count;@ @ @ @ @ /* how many elements */ @itemx @ @ @ @ awk_element_t elements[1];@ @ /* will be extended */ @itemx @} awk_flat_array_t; @@ -31843,7 +32242,7 @@ The following functions relate to individual array elements. @table @code @item awk_bool_t get_element_count(awk_array_t a_cookie, size_t *count); -For the array represented by @code{a_cookie}, return in @code{*count} +For the array represented by @code{a_cookie}, place in @code{*count} the number of elements it contains. A subarray counts as a single element. Return false if there is an error. @@ -31863,7 +32262,8 @@ requires that you understand how such values are converted to strings (@pxref{Conversion}); thus using integral values is safest. As with @emph{all} strings passed into @code{gawk} from an extension, -the string value of @code{index} must come from the API-provided functions @code{api_malloc()}, @code{api_calloc()} or @code{api_realloc()} and +the string value of @code{index} must come from @code{gawk_malloc()}, +@code{gawk_calloc()} or @code{gawk_realloc()}, and @command{gawk} releases the storage. @item awk_bool_t set_array_element(awk_array_t a_cookie, @@ -31890,7 +32290,7 @@ not exist in the array. The following functions relate to arrays as a whole: @table @code -@item awk_array_t create_array(); +@item awk_array_t create_array(void); Create a new array to which elements may be added. @xref{Creating Arrays}, for a discussion of how to create a new array and add elements to it. @@ -31907,7 +32307,13 @@ For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t} structure and fill it in. Set the pointer whose address is passed as @code{data} to point to this structure. Return true upon success, or false otherwise. -@xref{Flattening Arrays}, for a discussion of how to +@ifset FOR_PRINT +See the next section +@end ifset +@ifclear FOR_PRINT +@xref{Flattening Arrays}, +@end ifclear +for a discussion of how to flatten an array and work with it. @item awk_bool_t release_flattened_array(awk_array_t a_cookie, @@ -31927,6 +32333,7 @@ for C code to traverse the entire array. Test code in @file{extension/testext.c} does this, and also serves as a nice example showing how to use the APIs. +We walk through that part of the code one step at a time. First, the @command{gawk} script that drives the test extension: @example @@ -32065,8 +32472,7 @@ have this flag bit set: valrep2str(& flat_array->elements[i].value)); if (strcmp(value3.str_value.str, - flat_array->elements[i].index.str_value.str) - == 0) @{ + flat_array->elements[i].index.str_value.str) == 0) @{ flat_array->elements[i].flags |= AWK_ELEMENT_DELETE; printf("dump_array_and_delete: marking element \"%s\" " "for deletion\n", @@ -32170,7 +32576,9 @@ of the array cookie after the call to @code{set_element()}. The following C code is a simple test extension to create an array with two regular elements and with a subarray. The leading @code{#include} -directives and boilerplate variable declarations are omitted for brevity. +directives and boilerplate variable declarations +(@pxref{Extension API Boilerplate}) +are omitted for brevity. The first step is to create a new array and then install it in the symbol table: @@ -32416,7 +32824,7 @@ This variable is true if @command{gawk} was invoked with @option{--traditional} @end table The value of @code{do_lint} can change if @command{awk} code -modifies the @code{LINT} built-in variable (@pxref{Built-in Variables}). +modifies the @code{LINT} predefined variable (@pxref{Built-in Variables}). The others should not change during execution. @node Extension API Boilerplate @@ -32449,12 +32857,12 @@ static awk_bool_t (*init_func)(void) = NULL; /* OR: */ static awk_bool_t -init_my_module(void) +init_my_extension(void) @{ @dots{} @} -static awk_bool_t (*init_func)(void) = init_my_module; +static awk_bool_t (*init_func)(void) = init_my_extension; dl_load_func(func_table, some_name, "name_space_in_quotes") @end example @@ -32497,8 +32905,8 @@ It can then be looped over for multiple calls to @c Use @var{OR} for docbook @item static awk_bool_t (*init_func)(void) = NULL; @itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @var{OR} -@itemx static awk_bool_t init_my_module(void) @{ @dots{} @} -@itemx static awk_bool_t (*init_func)(void) = init_my_module; +@itemx static awk_bool_t init_my_extension(void) @{ @dots{} @} +@itemx static awk_bool_t (*init_func)(void) = init_my_extension; If you need to do some initialization work, you should define a function that does it (creates variables, opens files, etc.) and then define the @code{init_func} pointer to point to your @@ -32565,8 +32973,8 @@ path with a list of directories to search for compiled extensions. Two useful functions that are not in @command{awk} are @code{chdir()} (so that an @command{awk} program can change its directory) and @code{stat()} (so that an @command{awk} program can gather information about a file). -This @value{SECTION} implements these functions for @command{gawk} -in an extension. +In order to illustrate the API in action, this @value{SECTION} implements +these functions for @command{gawk} in an extension. @menu * Internal File Description:: What the new functions will do. @@ -32588,8 +32996,7 @@ straightforward. It takes one argument, the new directory to change to: newdir = "/home/arnold/funstuff" ret = chdir(newdir) if (ret < 0) @{ - printf("could not change to %s: %s\n", - newdir, ERRNO) > "/dev/stderr" + printf("could not change to %s: %s\n", newdir, ERRNO) > "/dev/stderr" exit 1 @} @dots{} @@ -32777,7 +33184,7 @@ The second is a pointer to an @code{awk_value_t}, usually named @code{result}. @example -/* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ +/* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * do_chdir(int nargs, awk_value_t *result) @@ -32986,13 +33393,22 @@ for success: @} @} - array_set(array, "type", make_const_string(type, strlen(type), &tmp)); + array_set(array, "type", make_const_string(type, strlen(type), & tmp)); return 0; @} @end example -Finally, here is the @code{do_stat()} function. It starts with +The third argument to @code{stat()} was not discussed previously. This +argument is optional. If present, it causes @code{do_stat()} to use +the @code{stat()} system call instead of the @code{lstat()} system +call. This is done by using a function pointer: @code{statfunc}. +@code{statfunc} is initialized to point to @code{lstat()} (instead +of @code{stat()}) to get the file information, in case the file is a +symbolic link. However, if there were three arguments, @code{statfunc} +is set point to @code{stat()}, instead. + +Here is the @code{do_stat()} function. It starts with variable declarations and argument checking: @ignore @@ -33023,16 +33439,10 @@ do_stat(int nargs, awk_value_t *result) @} @end example -The third argument to @code{stat()} was not discussed previously. This argument -is optional. If present, it causes @code{stat()} to use the @code{stat()} -system call instead of the @code{lstat()} system call. - Then comes the actual work. First, the function gets the arguments. -Next, it gets the information for the file. -The code use @code{lstat()} (instead of @code{stat()}) -to get the file information, -in case the file is a symbolic link. -If there's an error, it sets @code{ERRNO} and returns: +Next, it gets the information for the file. If the called function +(@code{lstat()} or @code{stat()}) returns an error, the code sets +@code{ERRNO} and returns: @example /* file is first arg, array to hold results is second */ @@ -33061,7 +33471,7 @@ If there's an error, it sets @code{ERRNO} and returns: @end example The tedious work is done by @code{fill_stat_array()}, shown -earlier. When done, return the result from @code{fill_stat_array()}: +earlier. When done, the function returns the result from @code{fill_stat_array()}: @example ret = fill_stat_array(name, array, & sbuf); @@ -33124,7 +33534,7 @@ of the @file{gawkapi.h} header file, the following steps@footnote{In practice, you would probably want to use the GNU Autotools---Automake, Autoconf, Libtool, and @command{gettext}---to configure and build your libraries. Instructions for doing so are beyond -the scope of this @value{DOCUMENT}. @xref{gawkextlib}, for WWW links to +the scope of this @value{DOCUMENT}. @xref{gawkextlib}, for Internet links to the tools.} create a GNU/Linux shared library: @example @@ -33152,14 +33562,14 @@ BEGIN @{ for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] print "testff.awk modified:", - strftime("%m %d %y %H:%M:%S", data["mtime"]) + strftime("%m %d %Y %H:%M:%S", data["mtime"]) print "\nInfo for JUNK" ret = stat("JUNK", data) print "ret =", ret for (i in data) printf "data[\"%s\"] = %s\n", i, data[i] - print "JUNK modified:", strftime("%m %d %y %H:%M:%S", data["mtime"]) + print "JUNK modified:", strftime("%m %d %Y %H:%M:%S", data["mtime"]) @} @end example @@ -33173,25 +33583,26 @@ $ @kbd{AWKLIBPATH=$PWD gawk -f testff.awk} @print{} Info for testff.awk @print{} ret = 0 @print{} data["blksize"] = 4096 -@print{} data["mtime"] = 1350838628 +@print{} data["devbsize"] = 512 +@print{} data["mtime"] = 1412004710 @print{} data["mode"] = 33204 @print{} data["type"] = file @print{} data["dev"] = 2053 @print{} data["gid"] = 1000 -@print{} data["ino"] = 1719496 -@print{} data["ctime"] = 1350838628 +@print{} data["ino"] = 10358899 +@print{} data["ctime"] = 1412004710 @print{} data["blocks"] = 8 @print{} data["nlink"] = 1 @print{} data["name"] = testff.awk -@print{} data["atime"] = 1350838632 +@print{} data["atime"] = 1412004716 @print{} data["pmode"] = -rw-rw-r-- -@print{} data["size"] = 662 +@print{} data["size"] = 666 @print{} data["uid"] = 1000 -@print{} testff.awk modified: 10 21 12 18:57:08 -@print{} +@print{} testff.awk modified: 09 29 2014 18:31:50 +@print{} @print{} Info for JUNK @print{} ret = -1 -@print{} JUNK modified: 01 01 70 02:00:00 +@print{} JUNK modified: 01 01 1970 02:00:00 @end example @node Extension Samples @@ -33216,9 +33627,9 @@ Others mainly provide example code that shows how to use the extension API. * Extension Sample Rev2way:: Reversing data sample two-way processor. * Extension Sample Read write array:: Serializing an array to a file. * Extension Sample Readfile:: Reading an entire file into a string. -* Extension Sample API Tests:: Tests for the API. * Extension Sample Time:: An interface to @code{gettimeofday()} and @code{sleep()}. +* Extension Sample API Tests:: Tests for the API. @end menu @node Extension Sample File Functions @@ -33228,7 +33639,7 @@ The @code{filefuncs} extension provides three different functions, as follows: The usage is: @table @asis -@item @@load "filefuncs" +@item @code{@@load "filefuncs"} This is how you load the extension. @cindex @code{chdir()} extension function @@ -33291,7 +33702,7 @@ Not all systems support all file types. @tab All @itemx @code{result = fts(pathlist, flags, filedata)} Walk the file trees provided in @code{pathlist} and fill in the @code{filedata} array as described below. @code{flags} is the bitwise -OR of several predefined constant values, also described below. +OR of several predefined values, also described below. Return zero if there were no errors, otherwise return @minus{}1. @end table @@ -33336,10 +33747,10 @@ Immediately follow a symbolic link named in @code{pathlist}, whether or not @code{FTS_LOGICAL} is set. @item FTS_SEEDOT -By default, the @code{fts()} routines do not return entries for @file{.} (dot) -and @file{..} (dot-dot). This option causes entries for dot-dot to also -be included. (The extension always includes an entry for dot, -see below.) +By default, the C library @code{fts()} routines do not return entries for +@file{.} (dot) and @file{..} (dot-dot). This option causes entries for +dot-dot to also be included. (The extension always includes an entry +for dot, see below.) @item FTS_XDEV During a traversal, do not cross onto a different mounted filesystem. @@ -33393,8 +33804,8 @@ Otherwise it returns @minus{}1. @quotation NOTE The @code{fts()} extension does not exactly mimic the interface of the C library @code{fts()} routines, choosing instead to -provide an interface that is based on associative arrays, which should -be more comfortable to use from an @command{awk} program. This includes the +provide an interface that is based on associative arrays, which is +more comfortable to use from an @command{awk} program. This includes the lack of a comparison function, since @command{gawk} already provides powerful array sorting facilities. While an @code{fts_read()}-like interface could have been provided, this felt less natural than simply @@ -33402,7 +33813,8 @@ creating a multidimensional array to represent the file hierarchy and its information. @end quotation -See @file{test/fts.awk} in the @command{gawk} distribution for an example. +See @file{test/fts.awk} in the @command{gawk} distribution for an example +use of the @code{fts()} extension function. @node Extension Sample Fnmatch @subsection Interface To @code{fnmatch()} @@ -33606,11 +34018,11 @@ The record consists of three fields. The first two are the inode number and the @value{FN}, separated by a forward slash character. On systems where the directory entry contains the file type, the record has a third field (also separated by a slash) which is a single letter -indicating the type of the file. The letters are file types are shown -in @ref{table-readdir-file-types}. +indicating the type of the file. The letters and their corresponding file +types are shown in @ref{table-readdir-file-types}. @float Table,table-readdir-file-types -@caption{File Types Returned By @code{readdir()}} +@caption{File Types Returned By The @code{readdir} Extension} @multitable @columnfractions .1 .9 @headitem Letter @tab File Type @item @code{b} @tab Block device @@ -33702,6 +34114,9 @@ The @code{rwarray} extension adds two functions, named @code{writea()} and @code{reada()}, as follows: @table @code +@item @@load "rwarray" +This is how you load the extension. + @cindex @code{writea()} extension function @item ret = writea(file, array) This function takes a string argument, which is the name of the file @@ -33777,17 +34192,6 @@ if (contents == "" && ERRNO != "") @{ @} @end example -@node Extension Sample API Tests -@subsection API Tests -@cindex @code{testext} extension - -The @code{testext} extension exercises parts of the extension API that -are not tested by the other samples. The @file{extension/testext.c} -file contains both the C code for the extension and @command{awk} -test code inside C comments that run the tests. The testing framework -extracts the @command{awk} code and runs the tests. See the source file -for more information. - @node Extension Sample Time @subsection Extension Time Functions @@ -33818,6 +34222,17 @@ Implementation details: depending on platform availability, this function tries to use @code{nanosleep()} or @code{select()} to implement the delay. @end table +@node Extension Sample API Tests +@subsection API Tests +@cindex @code{testext} extension + +The @code{testext} extension exercises parts of the extension API that +are not tested by the other samples. The @file{extension/testext.c} +file contains both the C code for the extension and @command{awk} +test code inside C comments that run the tests. The testing framework +extracts the @command{awk} code and runs the tests. See the source file +for more information. + @node gawkextlib @section The @code{gawkextlib} Project @cindex @code{gawkextlib} @@ -33833,8 +34248,7 @@ As of this writing, there are five extensions: @itemize @value{BULLET} @item -XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} -XML parsing library. +GD graphics library extension. @item PDF extension. @@ -33843,17 +34257,14 @@ PDF extension. PostgreSQL extension. @item -GD graphics library extension. - -@item MPFR library extension. This provides access to a number of MPFR functions which @command{gawk}'s native MPFR support does not. -@end itemize -The @code{time} extension described earlier (@pxref{Extension Sample -Time}) was originally from this project but has been moved in to the -main @command{gawk} distribution. +@item +XML parser extension, using the @uref{http://expat.sourceforge.net, Expat} +XML parsing library. +@end itemize @cindex @command{git} utility You can check out the code for the @code{gawkextlib} project @@ -33930,7 +34341,7 @@ certain tasks. @item One of these tasks is to ``register'' the name and implementation of -a new @command{awk}-level function with @command{gawk}. The implementation +new @command{awk}-level functions with @command{gawk}. The implementation takes the form of a C function pointer with a defined signature. By convention, implementation functions are named @code{do_@var{XXXX}()} for some @command{awk}-level function @code{@var{XXXX}()}. @@ -33944,6 +34355,9 @@ API function pointers are provided for the following kinds of operations: @itemize @value{BULLET} @item +Allocating, reallocating, and releasing memory. + +@item Registration functions. You may register extension functions, exit callbacks, @@ -33967,9 +34381,6 @@ Symbol table access: retrieving a global variable, creating one, or changing one. @item -Allocating, reallocating, and releasing memory. - -@item Creating and releasing cached values; this provides an efficient way to use values for multiple variables and can be a big performance win. @@ -33981,7 +34392,7 @@ getting the count of elements in an array; creating a new array; clearing an array; and -flattening an array for easy C style looping over all its indices and elements +flattening an array for easy C style looping over all its indices and elements. @end itemize @item @@ -34001,7 +34412,7 @@ treated as read-only by the extension. @item @emph{All} memory passed from an extension to @command{gawk} must come from the API's memory allocation functions. @command{gawk} takes responsibility for -the memory and will release it when appropriate. +the memory and releases it when appropriate. @item The API provides information about the running version of @command{gawk} so @@ -34018,7 +34429,7 @@ The @command{gawk} distribution includes a number of small but useful sample extensions. The @code{gawkextlib} project includes several more, larger, extensions. If you wish to write an extension and contribute it to the community of @command{gawk} users, the @code{gawkextlib} project -should be the place to do so. +is the place to do so. @end itemize @@ -34100,7 +34511,7 @@ which follows the POSIX specification. Many long-time @command{awk} users learned @command{awk} programming with the original @command{awk} implementation in Version 7 Unix. (This implementation was the basis for @command{awk} in Berkeley Unix, through 4.3-Reno. Subsequent versions -of Berkeley Unix, and some systems derived from 4.4BSD-Lite, used various +of Berkeley Unix, and, for a while, some systems derived from 4.4BSD-Lite, used various versions of @command{gawk} for their @command{awk}.) This @value{CHAPTER} briefly describes the evolution of the @command{awk} language, with cross-references to other parts of the @value{DOCUMENT} where you can @@ -34173,7 +34584,7 @@ The built-in functions @code{close()} and @code{system()} @item The @code{ARGC}, @code{ARGV}, @code{FNR}, @code{RLENGTH}, @code{RSTART}, -and @code{SUBSEP} built-in variables (@pxref{Built-in Variables}). +and @code{SUBSEP} predefined variables (@pxref{Built-in Variables}). @item Assignable @code{$0} (@pxref{Changing Fields}). @@ -34204,14 +34615,11 @@ of @code{FS}. @item Dynamic regexps as operands of the @samp{~} and @samp{!~} operators -(@pxref{Regexp Usage}). +(@pxref{Computed Regexps}). @item The escape sequences @samp{\b}, @samp{\f}, and @samp{\r} (@pxref{Escape Sequences}). -(Some vendors have updated their old versions of @command{awk} to -recognize @samp{\b}, @samp{\f}, and @samp{\r}, but this is not -something you can rely on.) @item Redirection of input for the @code{getline} function @@ -34250,7 +34658,7 @@ The @option{-v} option for assigning variables before program execution begins @c GNU, Bell Laboratories & MKS together @item -The @option{--} option for terminating command-line options. +The @option{--} signal for terminating command-line options. @item The @samp{\a}, @samp{\v}, and @samp{\x} escape sequences @@ -34267,13 +34675,13 @@ for case translation (@pxref{String Functions}). @item -A cleaner specification for the @samp{%c} format-control letter in the +A cleaner specification for the @code{%c} format-control letter in the @code{printf} function (@pxref{Control Letters}). @item The ability to dynamically pass the field width and precision (@code{"%*.*d"}) -in the argument list of the @code{printf} function +in the argument list of @code{printf} and @code{sprintf()} (@pxref{Control Letters}). @item @@ -34308,8 +34716,8 @@ The concept of a numeric string and tighter comparison rules to go with it (@pxref{Typing and Comparison}). @item -The use of built-in variables as function parameter names is forbidden -(@pxref{Definition Syntax}. +The use of predefined variables as function parameter names is forbidden +(@pxref{Definition Syntax}). @item More complete documentation of many of the previously undocumented @@ -34404,7 +34812,7 @@ in the current version of @command{gawk}. @itemize @value{BULLET} @item -Additional built-in variables: +Additional predefined variables: @itemize @value{MINUS} @item @@ -34488,14 +34896,6 @@ The @code{BEGINFILE} and @code{ENDFILE} special patterns. (@pxref{BEGINFILE/ENDFILE}). @item -The ability to delete all of an array at once with @samp{delete @var{array}} -(@pxref{Delete}). - -@item -The @code{nextfile} statement -(@pxref{Nextfile Statement}). - -@item The @code{switch} statement (@pxref{Switch Statement}). @end itemize @@ -34510,7 +34910,7 @@ of a two-way pipe to a coprocess (@pxref{Two-way I/O}). @item -POSIX compliance for @code{gsub()} and @code{sub()}. +POSIX compliance for @code{gsub()} and @code{sub()} with @option{--posix}. @item The @code{length()} function accepts an array argument @@ -34538,6 +34938,20 @@ Additional functions only in @command{gawk}: @itemize @value{MINUS} @item +The @code{gensub()}, @code{patsplit()}, and @code{strtonum()} functions +for more powerful text manipulation +(@pxref{String Functions}). + +@item +The @code{asort()} and @code{asorti()} functions for sorting arrays +(@pxref{Array Sorting}). + +@item +The @code{mktime()}, @code{systime()}, and @code{strftime()} +functions for working with timestamps +(@pxref{Time Functions}). + +@item The @code{and()}, @code{compl()}, @@ -34551,30 +34965,15 @@ functions for bit manipulation @c In 4.1, and(), or() and xor() grew the ability to take > 2 arguments @item -The @code{asort()} and @code{asorti()} functions for sorting arrays -(@pxref{Array Sorting}). +The @code{isarray()} function to check if a variable is an array or not +(@pxref{Type Functions}). @item The @code{bindtextdomain()}, @code{dcgettext()} and @code{dcngettext()} functions for internationalization (@pxref{Programmer i18n}). - -@item -The @code{fflush()} function from BWK @command{awk} -(@pxref{I/O Functions}). - -@item -The @code{gensub()}, @code{patsplit()}, and @code{strtonum()} functions -for more powerful text manipulation -(@pxref{String Functions}). - -@item -The @code{mktime()}, @code{systime()}, and @code{strftime()} -functions for working with timestamps -(@pxref{Time Functions}). @end itemize - @item Changes and/or additions in the command-line options: @@ -34697,7 +35096,7 @@ GCC for VAX and Alpha has not been tested for a while. @item Support for the following obsolete systems was removed from the code -and the documentation for @command{gawk} @value{PVERSION} 4.1: +for @command{gawk} @value{PVERSION} 4.1: @c nested table @itemize @value{MINUS} @@ -35301,7 +35700,7 @@ The @option{-l} and @option{--load} options load compiled dynamic extensions. The @option{-M} and @option{--bignum} options enable MPFR. @item -The @option{-o} only does pretty-printing. +The @option{-o} option only does pretty-printing. @item The @option{-p} option is used for profiling. @@ -35334,33 +35733,29 @@ The dynamic extension interface was completely redone @cindex extensions, Brian Kernighan's @command{awk} @cindex extensions, @command{mawk} -This @value{SECTION} summarizes the common extensions supported +The following table summarizes the common extensions supported by @command{gawk}, Brian Kernighan's @command{awk}, and @command{mawk}, the three most widely-used freely available versions of @command{awk} (@pxref{Other Versions}). -@multitable {@file{/dev/stderr} special file} {BWK Awk} {Mawk} {GNU Awk} -@headitem Feature @tab BWK Awk @tab Mawk @tab GNU Awk -@item @samp{\x} Escape sequence @tab X @tab X @tab X -@item @code{FS} as null string @tab X @tab X @tab X -@item @file{/dev/stdin} special file @tab X @tab X @tab X -@item @file{/dev/stdout} special file @tab X @tab X @tab X -@item @file{/dev/stderr} special file @tab X @tab X @tab X -@item @code{delete} without subscript @tab X @tab X @tab X -@item @code{fflush()} function @tab X @tab X @tab X -@item @code{length()} of an array @tab X @tab X @tab X -@item @code{nextfile} statement @tab X @tab X @tab X -@item @code{**} and @code{**=} operators @tab X @tab @tab X -@item @code{func} keyword @tab X @tab @tab X -@item @code{BINMODE} variable @tab @tab X @tab X -@item @code{RS} as regexp @tab @tab X @tab X -@item Time related functions @tab @tab X @tab X +@multitable {@file{/dev/stderr} special file} {BWK Awk} {Mawk} {GNU Awk} {Now standard} +@headitem Feature @tab BWK Awk @tab Mawk @tab GNU Awk @tab Now standard +@item @samp{\x} Escape sequence @tab X @tab X @tab X @tab +@item @code{FS} as null string @tab X @tab X @tab X @tab +@item @file{/dev/stdin} special file @tab X @tab X @tab X @tab +@item @file{/dev/stdout} special file @tab X @tab X @tab X @tab +@item @file{/dev/stderr} special file @tab X @tab X @tab X @tab +@item @code{delete} without subscript @tab X @tab X @tab X @tab X +@item @code{fflush()} function @tab X @tab X @tab X @tab X +@item @code{length()} of an array @tab X @tab X @tab X @tab +@item @code{nextfile} statement @tab X @tab X @tab X @tab X +@item @code{**} and @code{**=} operators @tab X @tab @tab X @tab +@item @code{func} keyword @tab X @tab @tab X @tab +@item @code{BINMODE} variable @tab @tab X @tab X @tab +@item @code{RS} as regexp @tab @tab X @tab X @tab +@item Time related functions @tab @tab X @tab X @tab @end multitable -(Technically speaking, as of late 2012, @code{fflush()}, @samp{delete @var{array}}, -and @code{nextfile} are no longer extensions, since they have been added -to POSIX.) - @node Ranges and Locales @appendixsec Regexp Ranges and Locales: A Long Sad Story @@ -35397,6 +35792,7 @@ In the @code{"C"} and @code{"POSIX"} locales, a range expression like But outside those locales, the ordering was defined to be based on @dfn{collation order}. +What does that mean? In many locales, @samp{A} and @samp{a} are both less than @samp{B}. In other words, these locales sort characters in dictionary order, and @samp{[a-dx-z]} is typically not equivalent to @samp{[abcdxyz]}; @@ -35404,7 +35800,7 @@ instead it might be equivalent to @samp{[ABCXYabcdxyz]}, for example. This point needs to be emphasized: Much literature teaches that you should use @samp{[a-z]} to match a lowercase character. But on systems with -non-ASCII locales, this also matched all of the uppercase characters +non-ASCII locales, this also matches all of the uppercase characters except @samp{A} or @samp{Z}! This was a continuous cause of confusion, even well into the twenty-first century. @@ -35594,7 +35990,7 @@ the various PC platforms. @cindex Zoulas, Christos Christos Zoulas provided the @code{extension()} -built-in function for dynamically adding new modules. +built-in function for dynamically adding new functions. (This was obsoleted at @command{gawk} 4.1.) @item @@ -35710,6 +36106,11 @@ The development of the extension API first released with Arnold Robbins and Andrew Schorr, with notable contributions from the rest of the development team. +@cindex Malmberg, John E. +@item +John Malmberg contributed significant improvements to the +OpenVMS port and the related documentation. + @item @cindex Colombo, Antonio Antonio Giovanni Colombo rewrote a number of examples in the early @@ -35771,7 +36172,7 @@ various platforms that are supported by the developers. The primary developer supports GNU/Linux (and Unix), whereas the other ports are contributed. @xref{Bugs}, -for the electronic mail addresses of the people who did +for the electronic mail addresses of the people who maintain the respective ports. @menu @@ -36046,6 +36447,12 @@ The source code, manual pages, and infrastructure files for the sample extensions included with @command{gawk}. @xref{Dynamic Extensions}, for more information. +@item extras/* +Additional non-essential files. Currently, this directory contains some shell +startup files to be installed in @file{/etc/profile.d} to aid in manipulating +the @env{AWKPATH} and @env{AWKLIBPATH} environment variables. +@xref{Shell Startup Files}, for more information. + @item posix/* Files needed for building @command{gawk} on POSIX-compliant systems. @@ -36078,6 +36485,7 @@ to configure @command{gawk} for your system yourself. @menu * Quick Installation:: Compiling @command{gawk} under Unix. +* Shell Startup Files:: Shell convenience functions. * Additional Configuration Options:: Other compile-time options. * Configuration Philosophy:: How it's all supposed to work. @end menu @@ -36090,11 +36498,10 @@ Unix-derived systems, GNU/Linux, BSD-based systems, and the Cygwin environment for MS-Windows. After you have extracted the @command{gawk} distribution, @command{cd} -to @file{gawk-@value{VERSION}.@value{PATCHLEVEL}}. Like most GNU software, -@command{gawk} is configured -automatically for your system by running the @command{configure} program. -This program is a Bourne shell script that is generated automatically using -GNU Autoconf. +to @file{gawk-@value{VERSION}.@value{PATCHLEVEL}}. As with most GNU +software, you configure @command{gawk} for your system by running the +@command{configure} program. This program is a Bourne shell script that +is generated automatically using GNU Autoconf. @ifnotinfo (The Autoconf software is described fully in @@ -36159,6 +36566,44 @@ is likely that you will be asked for your password, and you will have to have been set up previously as a user who is allowed to run the @command{sudo} command. +@node Shell Startup Files +@appendixsubsec Shell Startup Files + +The distribution contains shell startup files @file{gawk.sh} and +@file{gawk.csh} containing functions to aid in manipulating +the @env{AWKPATH} and @env{AWKLIBPATH} environment variables. +On a Fedora system, these files should be installed in @file{/etc/profile.d}; +on other platforms, the appropriate location may be different. + +@table @command + +@cindex @command{gawkpath_default} shell function +@item gawkpath_default +Reset the @env{AWKPATH} environment variable to its default value. + +@cindex @command{gawkpath_prepend} shell function +@item gawkpath_prepend +Add the argument to the front of the @env{AWKPATH} environment variable. + +@cindex @command{gawkpath_append} shell function +@item gawkpath_append +Add the argument to the end of the @env{AWKPATH} environment variable. + +@cindex @command{gawklibpath_default} shell function +@item gawklibpath_default +Reset the @env{AWKLIBPATH} environment variable to its default value. + +@cindex @command{gawklibpath_prepend} shell function +@item gawklibpath_prepend +Add the argument to the front of the @env{AWKLIBPATH} environment variable. + +@cindex @command{gawklibpath_append} shell function +@item gawklibpath_append +Add the argument to the end of the @env{AWKLIBPATH} environment variable. + +@end table + + @node Additional Configuration Options @appendixsubsec Additional Configuration Options @cindex @command{gawk}, configuring, options @@ -36189,8 +36634,8 @@ Similarly, setting the @code{LINT} variable has no effect on the running @command{awk} program. When used with GCC's automatic dead-code-elimination, this option -cuts almost 200K bytes off the size of the @command{gawk} -executable on GNU/Linux x86 systems. Results on other systems and +cuts almost 23K bytes off the size of the @command{gawk} +executable on GNU/Linux x86_64 systems. Results on other systems and with other compilers are likely to vary. Using this option may bring you some slight performance improvement. @@ -36283,7 +36728,8 @@ various non-Unix systems. @cindex PC operating systems@comma{} @command{gawk} on, installing @cindex operating systems, PC@comma{} @command{gawk} on, installing -This @value{SECTION} covers installation and usage of @command{gawk} on x86 machines +This @value{SECTION} covers installation and usage of @command{gawk} +on Intel architecture machines @ifclear FOR_PRINT running MS-DOS, any version of MS-Windows, or OS/2. @end ifclear @@ -36385,7 +36831,8 @@ MS-DOS and Windows32 versions. A list of targets is printed if the build @command{gawk} using the DJGPP tools, enter @samp{make djgpp}. (The DJGPP tools needed for the build may be found at @uref{ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/}.) To build a -native MS-Windows binary of @command{gawk}, type @samp{make mingw32}. +native MS-Windows binary of @command{gawk} using the MinGW tools, +type @samp{make mingw32}. @ifclear FOR_PRINT @cindex compiling @command{gawk} with EMX for OS/2 @@ -36508,15 +36955,14 @@ EMX (OS/2 only) supports at least the @samp{|&} operator. @cindex search paths, for source files @cindex @command{gawk}, MS-DOS version of @cindex @command{gawk}, MS-Windows version of -@cindex @code{;} (semicolon), @code{AWKPATH} variable and -@cindex semicolon (@code{;}), @code{AWKPATH} variable and +@cindex @code{;} (semicolon), @env{AWKPATH} variable and +@cindex semicolon (@code{;}), @env{AWKPATH} variable and @cindex @env{AWKPATH} environment variable The MS-DOS and MS-Windows versions of @command{gawk} search for program files as described in @ref{AWKPATH Variable}. However, semicolons (rather than colons) separate elements in the @env{AWKPATH} variable. If @env{AWKPATH} is not set or is empty, then the default -search path for MS-Windows and MS-DOS versions is -@samp{@w{.;c:/lib/awk;c:/gnu/lib/awk}}. +search path is @samp{@w{.;c:/lib/awk;c:/gnu/lib/awk}}. @ifclear FOR_PRINT @cindex @command{gawk}, OS/2 version of @@ -36561,12 +37007,12 @@ allows control over these translations and is interpreted as follows: @itemize @value{BULLET} @item -If @code{BINMODE} is @code{"r"}, or one, +If @code{BINMODE} is @code{"r"} or one, then binary mode is set on read (i.e., no translations on reads). @item -If @code{BINMODE} is @code{"w"}, or two, +If @code{BINMODE} is @code{"w"} or two, then binary mode is set on write (i.e., no translations on writes). @@ -36654,7 +37100,7 @@ same as for a Unix system: tar -xvpzf gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz cd gawk-@value{VERSION}.@value{PATCHLEVEL} ./configure -make +make && make check @end example When compared to GNU/Linux on the same system, the @samp{configure} @@ -36670,10 +37116,10 @@ need to use the @code{BINMODE} variable. This can cause problems with other Unix-like components that have been ported to MS-Windows that expect @command{gawk} to do automatic -translation of @code{"\r\n"}, since it won't. Caveat Emptor! +translation of @code{"\r\n"}, since it won't. @node VMS Installation -@appendixsubsec How to Compile and Install @command{gawk} on Vax/VMS and OpenVMS +@appendixsubsec Compiling and Installing @command{gawk} on Vax/VMS and OpenVMS @c based on material from Pat Rankin <rankin@eql.caltech.edu> @c now rankin@pactechdata.com @@ -36778,7 +37224,7 @@ For VAX: @end example Compile time macros need to be defined before the first VMS-supplied -header file is included. +header file is included, as follows: @example #if (__CRTL_VER >= 70200000) && !defined (__VAX) @@ -36794,6 +37240,11 @@ header file is included. #endif @end example +If you are writing your own extensions to run on VMS, you must supply these +definitions yourself. The @file{config.h} file created when building @command{gawk} +on VMS does this for you; if instead you use that file or a similar one, then you +must remember to include it before any VMS-supplied header files. + @node VMS Installation Details @appendixsubsubsec Installing @command{gawk} on VMS @@ -36890,12 +37341,12 @@ other dash-type options (or multiple parameters such as @value{DF}s to process) are present, there is no ambiguity and @option{--} can be omitted. @cindex exit status, of VMS -The @code{exit} value is a Unix-style value and is encoded to a VMS exit +The @code{exit} value is a Unix-style value and is encoded into a VMS exit status value when the program exits. The VMS severity bits will be set based on the @code{exit} value. A failure is indicated by 1 and VMS sets the @code{ERROR} status. -A fatal error is indicated by 2 and VMS will set the @code{FATAL} status. +A fatal error is indicated by 2 and VMS sets the @code{FATAL} status. All other values will have the @code{SUCCESS} status. The exit value is encoded to comply with VMS coding standards and will have the @code{C_FACILITY_NO} of @code{0x350000} with the constant @code{0xA000} @@ -36911,7 +37362,7 @@ unix_status = (vms_status .and. &x7f8) / 8 A C program that uses @code{exec()} to call @command{gawk} will get the original Unix-style exit value. -Older versions of @command{gawk} treated a Unix exit code 0 as 1, a failure +Older versions of @command{gawk} for VMS treated a Unix exit code 0 as 1, a failure as 2, a fatal error as 4, and passed all the other numbers through. This violated the VMS exit status coding requirements. @@ -36945,8 +37396,8 @@ See @w{@uref{https://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/}.} The normal build procedure for @command{gawk} produces a program that is suitable for use with GNV. -The @file{vms/gawk_build_steps.txt} in the source documents the procedure -for building a VMS PCSI kit that is compatible with GNV. +The file @file{vms/gawk_build_steps.txt} in the distribution documents +the procedure for building a VMS PCSI kit that is compatible with GNV. @ignore @c The VMS POSIX product, also known as POSIX for OpenVMS, is long defunct @@ -37018,8 +37469,8 @@ If you have problems with @command{gawk} or think that you have found a bug, please report it to the developers; we cannot promise to do anything but we might well want to fix it. -Before reporting a bug, make sure you have actually found a real bug. -Carefully reread the documentation and see if it really says you can do +Before reporting a bug, please make sure you have really found a genuine bug. +Carefully reread the documentation and see if it says you can do what you're trying to do. If it's not clear whether you should be able to do something or not, report that too; it's a bug in the documentation! @@ -37037,17 +37488,15 @@ You can get this information with the command @samp{gawk --version}. @cindex @code{bug-gawk@@gnu.org} bug reporting address @cindex email address for bug reports, @code{bug-gawk@@gnu.org} @cindex bug reports, email address, @code{bug-gawk@@gnu.org} -Once you have a precise problem, send email to +Once you have a precise problem description, send email to @EMAIL{bug-gawk@@gnu.org,bug-gawk at gnu dot org}. -@cindex Robbins, Arnold The @command{gawk} maintainers subscribe to this address and thus they will receive your bug report. -If necessary, the primary maintainer can be reached directly at -@EMAIL{arnold@@skeeve.com,arnold at skeeve dot com}. -The bug reporting address is preferred since the +Although you can send mail to the maintainers directly, +the bug reporting address is preferred since the email list is archived at the GNU Project. -@emph{All email should be in English. This is the only language +@emph{All email must be in English. This is the only language understood in common by all the maintainers.} @cindex @code{comp.lang.awk} newsgroup @@ -37056,7 +37505,7 @@ Do @emph{not} try to report bugs in @command{gawk} by posting to the Usenet/Internet newsgroup @code{comp.lang.awk}. While the @command{gawk} developers do occasionally read this newsgroup, there is no guarantee that we will see your posting. The steps described -above are the official recognized ways for reporting bugs. +above are the only official recognized way for reporting bugs. Really. @end quotation @@ -37068,35 +37517,34 @@ bug reporting system, @emph{please} also send a copy to This is for two reasons. First, while some distributions forward bug reports ``upstream'' to the GNU mailing list, many don't, so there is a good -chance that the @command{gawk} maintainer won't even see the bug report! Second, +chance that the @command{gawk} maintainers won't even see the bug report! Second, mail to the GNU list is archived, and having everything at the GNU project -keeps things self-contained and not dependant on other web sites. +keeps things self-contained and not dependant on other organizations. @end quotation Non-bug suggestions are always welcome as well. If you have questions about things that are unclear in the documentation or are just obscure -features, ask me; I will try to help you out, although I -may not have the time to fix the problem. You can send me electronic -mail at the Internet address noted previously. - -If you find bugs in one of the non-Unix ports of @command{gawk}, please send -an electronic mail message to the person who maintains that port. They -are named in the following list, as well as in the @file{README} file -in the @command{gawk} distribution. Information in the @file{README} -file should be considered authoritative if it conflicts with this -@value{DOCUMENT}. +features, ask on the bug list; we will try to help you out if we can. -The people maintaining the non-Unix ports of @command{gawk} are -as follows: +If you find bugs in one of the non-Unix ports of @command{gawk}, please +send an electronic mail message to the bug list, with a copy to the +person who maintains that port. They are named in the following list, +as well as in the @file{README} file in the @command{gawk} distribution. +Information in the @file{README} file should be considered authoritative +if it conflicts with this @value{DOCUMENT}. + +The people maintaining the various @command{gawk} ports are: @c put the index entries outside the table, for docbook -@cindex Deifik, Scott -@cindex Zaretskii, Eli @cindex Buening, Andreas -@cindex Rankin, Pat +@cindex Deifik, Scott @cindex Malmberg, John @cindex Pitts, Dave +@cindex Robbins, Arnold +@cindex Zaretskii, Eli @multitable {MS-Windows with MinGW} {123456789012345678901234567890123456789001234567890} +@item Unix and POSIX systems @tab Arnold Robbins, @EMAIL{arnold@@skeeve.com,arnold at skeeve dot com}. + @item MS-DOS with DJGPP @tab Scott Deifik, @EMAIL{scottd.mail@@sbcglobal.net,scottd dot mail at sbcglobal dot net}. @item MS-Windows with MinGW @tab Eli Zaretskii, @EMAIL{eliz@@gnu.org,eliz at gnu dot org}. @@ -37105,8 +37553,7 @@ as follows: @c OS/2 is not mentioned anywhere else in the print version though. @item OS/2 @tab Andreas Buening, @EMAIL{andreas.buening@@nexgo.de,andreas dot buening at nexgo dot de}. -@item VMS @tab Pat Rankin, @EMAIL{r.pat.rankin@@gmail.com,r.pat.rankin at gmail.com}, and -John Malmberg, @EMAIL{wb8tyw@@qsl.net,wb8tyw at qsl.net}. +@item VMS @tab John Malmberg, @EMAIL{wb8tyw@@qsl.net,wb8tyw at qsl.net}. @item z/OS (OS/390) @tab Dave Pitts, @EMAIL{dpitts@@cozx.com,dpitts at cozx dot com}. @end multitable @@ -37139,15 +37586,11 @@ Date: Wed, 4 Sep 1996 08:11:48 -0700 (PDT) @docbook <blockquote><attribution>Michael Brennan</attribution> -<literallayout> -<emphasis>It's kind of fun to put comments like this in your awk code.</emphasis> - <literal>// Do C++ comments work? answer: yes! of course</literal> -</literallayout> +<literallayout><emphasis>It's kind of fun to put comments like this in your awk code.</emphasis> + <literal>// Do C++ comments work? answer: yes! of course</literal></literallayout> </blockquote> @end docbook - - There are a number of other freely available @command{awk} implementations. This @value{SECTION} briefly describes where to get them: @@ -37252,7 +37695,7 @@ since approximately 2003. @item @command{pawk} Nelson H.F.@: Beebe at the University of Utah has modified BWK @command{awk} to provide timing and profiling information. -It is different from @command{gawk} with the @option{--profile} option. +It is different from @command{gawk} with the @option{--profile} option (@pxref{Profiling}), in that it uses CPU-based profiling, not line-count profiling. You may find it at either @@ -37277,7 +37720,7 @@ information, see the @uref{http://busybox.net, project's home page}. The versions of @command{awk} in @file{/usr/xpg4/bin} and @file{/usr/xpg6/bin} on Solaris are more-or-less POSIX-compliant. They are based on the @command{awk} from Mortice Kern Systems for PCs. -This author was able to make this code compile and work under GNU/Linux +We were able to make this code compile and work under GNU/Linux with 1--2 hours of work. Making it more generally portable (using GNU Autoconf and/or Automake) would take more work, and this has not been done, at least to our knowledge. @@ -37504,7 +37947,7 @@ make it possible to include them: @enumerate 1 @item Before building the new feature into @command{gawk} itself, -consider writing it as an extension module +consider writing it as an extension (@pxref{Dynamic Extensions}). If that's not possible, continue with the rest of the steps in this list. @@ -37749,7 +38192,7 @@ and @item Be willing to continue to maintain the port. Non-Unix operating systems are supported by volunteers who maintain -the code needed to compile and run @command{gawk} on their systems. If noone +the code needed to compile and run @command{gawk} on their systems. If no-one volunteers to maintain a port, it becomes unsupported and it may be necessary to remove it from the distribution. @@ -38235,7 +38678,7 @@ Pat Rankin suggested the solution that was adopted. @appendixsubsec Other Design Decisions As an arbitrary design decision, extensions can read the values of -built-in variables and arrays (such as @code{ARGV} and @code{FS}), but cannot +predefined variables and arrays (such as @code{ARGV} and @code{FS}), but cannot change them, with the exception of @code{PROCINFO}. The reason for this is to prevent an extension function from affecting @@ -38729,6 +39172,11 @@ originally written by Steven R.@: Bourne at Bell Laboratories. Many shells (Bash, @command{ksh}, @command{pdksh}, @command{zsh}) are generally upwardly compatible with the Bourne shell. +@item Braces +The characters @samp{@{} and @samp{@}}. Braces are used in +@command{awk} for delimiting actions, compound statements, and function +bodies. + @item Built-in Function The @command{awk} language provides built-in functions that perform various numerical, I/O-related, and string computations. Examples are @@ -38774,11 +39222,6 @@ are the variables that have special meaning to @command{gawk}. Changing some of them affects @command{awk}'s running environment. (@xref{Built-in Variables}.) -@item Braces -The characters @samp{@{} and @samp{@}}. Braces are used in -@command{awk} for delimiting actions, compound statements, and function -bodies. - @item C The system programming language that most GNU software is written in. The @command{awk} programming language has C-like syntax, and this @value{DOCUMENT} @@ -38976,11 +39419,11 @@ See ``Free Documentation License.'' @item Field When @command{awk} reads an input record, it splits the record into pieces separated by whitespace (or by a separator regexp that you can -change by setting the built-in variable @code{FS}). Such pieces are +change by setting the predefined variable @code{FS}). Such pieces are called fields. If the pieces are of fixed length, you can use the built-in variable @code{FIELDWIDTHS} to describe their lengths. If you wish to specify the contents of fields instead of the field -separator, you can use the built-in variable @code{FPAT} to do so. +separator, you can use the predefined variable @code{FPAT} to do so. (@xref{Field Separators}, @ref{Constant Size}, and @@ -38999,7 +39442,7 @@ See also ``Double Precision'' and ``Single Precision.'' Format strings control the appearance of output in the @code{strftime()} and @code{sprintf()} functions, and in the @code{printf} statement as well. Also, data conversions from numbers to strings -are controlled by the format strings contained in the built-in variables +are controlled by the format strings contained in the predefined variables @code{CONVFMT} and @code{OFMT}. (@xref{Control Letters}.) @item Free Documentation License @@ -40678,6 +41121,7 @@ Consistency issues: Use --foo, not -Wfoo when describing long options Use "Bell Laboratories", but not "Bell Labs". Use "behavior" instead of "behaviour". + Use "coprocess" instead of "co-process". Use "zeros" instead of "zeroes". Use "nonzero" not "non-zero". Use "runtime" not "run time" or "run-time". @@ -40782,4 +41226,4 @@ But to use it you have to say which sorta sucks. TODO: ------ +Check that all dark corners are indexed properly. @@ -362,6 +362,7 @@ static struct optypetab { { "Op_after_beginfile", NULL }, { "Op_after_endfile", NULL }, { "Op_func", NULL }, + { "Op_comment", NULL }, { "Op_exec_count", NULL }, { "Op_breakpoint", NULL }, { "Op_lint", NULL }, @@ -397,6 +397,9 @@ close_extensions() { SRCFILE *s; + if (srcfiles == NULL) + return; + for (s = srcfiles->next; s != srcfiles; s = s->next) if (s->stype == SRC_EXTLIB && s->fini_func) (*s->fini_func)(); diff --git a/extension/ChangeLog b/extension/ChangeLog index c7974e48..82ae5b69 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,13 @@ +2014-10-08 Arnold D. Robbins <arnold@skeeve.com> + + * inplace.c (do_inplace_begin): Use a cast to void in front + of the second call to chown to avoid compiler warnings from clang. + +2014-09-29 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c: Minor edits to sync with documentation. + * testext.c: Add test to get PROCINFO, expected to fail. + 2014-08-12 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (RM): Define for makes that don't have it, diff --git a/extension/filefuncs.c b/extension/filefuncs.c index d5249a4e..a20e9ff7 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -145,7 +145,7 @@ static const char *ext_version = "filefuncs extension: version 1.0"; int plugin_is_GPL_compatible; -/* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ +/* do_chdir --- provide dynamically loaded chdir() function for gawk */ static awk_value_t * do_chdir(int nargs, awk_value_t *result) @@ -448,7 +448,7 @@ fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf) } } - array_set(array, "type", make_const_string(type, strlen(type), &tmp)); + array_set(array, "type", make_const_string(type, strlen(type), & tmp)); return 0; } diff --git a/extension/inplace.c b/extension/inplace.c index e2f8b73f..8a7375c4 100644 --- a/extension/inplace.c +++ b/extension/inplace.c @@ -171,9 +171,8 @@ do_inplace_begin(int nargs, awk_value_t *result) /* N.B. chown/chmod should be more portable than fchown/fchmod */ if (chown(state.tname, sbuf.st_uid, sbuf.st_gid) < 0) - /* checking chown here shuts up the compiler. bleah */ - if (chown(state.tname, -1, sbuf.st_gid) < 0) - ; + (void) chown(state.tname, -1, sbuf.st_gid); + if (chmod(state.tname, sbuf.st_mode) < 0) fatal(ext_id, _("inplace_begin: chmod failed (%s)"), strerror(errno)); diff --git a/extension/testext.c b/extension/testext.c index 2dda339f..7462265b 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -302,6 +302,12 @@ var_test(int nargs, awk_value_t *result) goto out; } + /* look up PROCINFO - should fail */ + if (sym_lookup("PROCINFO", AWK_ARRAY, & value)) + printf("var_test: sym_lookup of PROCINFO failed - got a value!\n"); + else + printf("var_test: sym_lookup of PROCINFO passed - did not get a value\n"); + /* look up a reserved variable - should pass */ if (sym_lookup("ARGC", AWK_NUMBER, & value)) printf("var_test: sym_lookup of ARGC passed - got a value!\n"); diff --git a/extras/ChangeLog b/extras/ChangeLog new file mode 100644 index 00000000..5f7d33ad --- /dev/null +++ b/extras/ChangeLog @@ -0,0 +1,3 @@ +2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am, gawk.sh, gawk.csh: New files. diff --git a/extras/Makefile.am b/extras/Makefile.am new file mode 100644 index 00000000..6a33ae04 --- /dev/null +++ b/extras/Makefile.am @@ -0,0 +1,29 @@ +# +# extras/Makefile.am --- automake input file for gawk +# +# Copyright (C) 2014 the Free Software Foundation, Inc. +# +# This file is part of GAWK, the GNU implementation of the +# AWK Programming Language. +# +# GAWK is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# GAWK is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# + +## Process this file with automake to produce Makefile.in. + +profiledir = $(sysconfdir)/profile.d +profile_DATA = gawk.sh gawk.csh + +EXTRA_DIST = $(profile_DATA) diff --git a/extras/Makefile.in b/extras/Makefile.in new file mode 100644 index 00000000..86a10745 --- /dev/null +++ b/extras/Makefile.in @@ -0,0 +1,515 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# extras/Makefile.am --- automake input file for gawk +# +# Copyright (C) 2014 the Free Software Foundation, Inc. +# +# This file is part of GAWK, the GNU implementation of the +# AWK Programming Language. +# +# GAWK is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# GAWK is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = extras +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/mkinstalldirs ChangeLog +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \ + $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ + $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \ + $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(profiledir)" +DATA = $(profile_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GAWKLIBEXT = @GAWKLIBEXT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_LIBSIGSEGV = @HAVE_LIBSIGSEGV@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBSIGSEGV = @LIBSIGSEGV@ +LIBSIGSEGV_PREFIX = @LIBSIGSEGV_PREFIX@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBSIGSEGV = @LTLIBSIGSEGV@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKET_LIBS = @SOCKET_LIBS@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +acl_shlibext = @acl_shlibext@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgextensiondir = @pkgextensiondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +profiledir = $(sysconfdir)/profile.d +profile_DATA = gawk.sh gawk.csh +EXTRA_DIST = $(profile_DATA) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu extras/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu extras/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-profileDATA: $(profile_DATA) + @$(NORMAL_INSTALL) + @list='$(profile_DATA)'; test -n "$(profiledir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(profiledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(profiledir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(profiledir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(profiledir)" || exit $$?; \ + done + +uninstall-profileDATA: + @$(NORMAL_UNINSTALL) + @list='$(profile_DATA)'; test -n "$(profiledir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(profiledir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(profiledir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-profileDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-profileDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic cscopelist-am \ + ctags-am distclean distclean-generic distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-profileDATA install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags-am uninstall uninstall-am \ + uninstall-profileDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extras/gawk.csh b/extras/gawk.csh new file mode 100644 index 00000000..583d5bcd --- /dev/null +++ b/extras/gawk.csh @@ -0,0 +1,11 @@ +alias gawkpath_default 'unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`' + +alias gawkpath_prepend 'if (! $?AWKPATH) setenv AWKPATH ""; if ($AWKPATH == "") then; unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKPATH "\!*"":$AWKPATH"' + +alias gawkpath_append 'if (! $?AWKPATH) setenv AWKPATH ""; if ($AWKPATH == "") then; unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKPATH "$AWKPATH"":\!*"' + +alias gawklibpath_default 'unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`' + +alias gawklibpath_prepend 'if (! $?AWKLIBPATH) setenv AWKLIBPATH ""; if ($AWKLIBPATH == "") then; unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKLIBPATH "\!*"":$AWKLIBPATH"' + +alias gawklibpath_append 'if (! $?AWKLIBPATH) setenv AWKLIBPATH ""; if ($AWKLIBPATH == "") then; unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKLIBPATH "$AWKLIBPATH"":\!*"' diff --git a/extras/gawk.sh b/extras/gawk.sh new file mode 100644 index 00000000..c35471fa --- /dev/null +++ b/extras/gawk.sh @@ -0,0 +1,31 @@ +gawkpath_default () { + unset AWKPATH + export AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'` +} + +gawkpath_prepend () { + [ -z "$AWKPATH" ] && AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'` + export AWKPATH="$*:$AWKPATH" +} + +gawkpath_append () { + [ -z "$AWKPATH" ] && AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'` + export AWKPATH="$AWKPATH:$*" +} + +gawklibpath_default () { + unset AWKLIBPATH + export AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'` +} + +gawklibpath_prepend () { + [ -z "$AWKLIBPATH" ] && \ + AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'` + export AWKLIBPATH="$*:$AWKLIBPATH" +} + +gawklibpath_append () { + [ -z "$AWKLIBPATH" ] && \ + AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'` + export AWKLIBPATH="$AWKLIBPATH:$*" +} @@ -883,17 +883,17 @@ static awk_bool_t (*init_func)(void) = NULL; /* OR: */ static awk_bool_t -init_my_module(void) +init_my_extension(void) { ... } -static awk_bool_t (*init_func)(void) = init_my_module; +static awk_bool_t (*init_func)(void) = init_my_extension; dl_load_func(func_table, some_name, "name_space_in_quotes") #endif -#define dl_load_func(func_table, module, name_space) \ +#define dl_load_func(func_table, extension, name_space) \ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) \ { \ size_t i, j; \ @@ -904,7 +904,7 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) \ \ if (api->major_version != GAWK_API_MAJOR_VERSION \ || api->minor_version < GAWK_API_MINOR_VERSION) { \ - fprintf(stderr, #module ": version mismatch with gawk!\n"); \ + fprintf(stderr, #extension ": version mismatch with gawk!\n"); \ fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, %d)\n", \ GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION, \ api->major_version, api->minor_version); \ @@ -916,7 +916,7 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) \ if (func_table[i].name == NULL) \ break; \ if (! add_ext_func(name_space, & func_table[i])) { \ - warning(ext_id, #module ": could not add %s\n", \ + warning(ext_id, #extension ": could not add %s\n", \ func_table[i].name); \ errors++; \ } \ @@ -924,7 +924,7 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) \ \ if (init_func != NULL) { \ if (! init_func()) { \ - warning(ext_id, #module ": initialization function failed\n"); \ + warning(ext_id, #extension ": initialization function failed\n"); \ errors++; \ } \ } \ diff --git a/interpret.h b/interpret.h index 28804330..23ce0c1a 100644 --- a/interpret.h +++ b/interpret.h @@ -1390,6 +1390,7 @@ match_re: case Op_K_if: case Op_K_else: case Op_cond_exp: + case Op_comment: break; default: @@ -1559,6 +1559,17 @@ nextrres: * change the string. */ +/* + * 9/2014: Flow here is a little messy. + * + * For do_posix, we don't allow any of the special filenames. + * + * For do_traditional, we allow /dev/{stdin,stdout,stderr} since BWK awk + * (and mawk) support them. But we don't allow /dev/fd/N or /inet. + * + * Note that for POSIX systems os_devopen() is a no-op. + */ + int devopen(const char *name, const char *mode) { @@ -1574,7 +1585,7 @@ devopen(const char *name, const char *mode) flag = str2mode(mode); openfd = INVALID_HANDLE; - if (do_traditional) + if (do_posix) goto strictopen; if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) { @@ -1591,6 +1602,8 @@ devopen(const char *name, const char *mode) openfd = fileno(stdout); else if (strcmp(cp, "stderr") == 0 && (flag & O_ACCMODE) == O_WRONLY) openfd = fileno(stderr); + else if (do_traditional) + goto strictopen; else if (strncmp(cp, "fd/", 3) == 0) { struct stat sbuf; @@ -1603,6 +1616,8 @@ devopen(const char *name, const char *mode) /* do not set close-on-exec for inherited fd's */ if (openfd != INVALID_HANDLE) return openfd; + } else if (do_traditional) { + goto strictopen; } else if (inetfile(name, & isi)) { #ifdef HAVE_SOCKETS cp = (char *) name; @@ -2537,7 +2552,6 @@ do_getline(int into_variable, IOBUF *iop) typedef struct { const char *envname; char **dfltp; /* pointer to address of default path */ - char try_cwd; /* always search current directory? */ char **awkpath; /* array containing library search paths */ int max_pathlen; /* length of the longest item in awkpath */ } path_info; @@ -2545,13 +2559,11 @@ typedef struct { static path_info pi_awkpath = { /* envname */ "AWKPATH", /* dfltp */ & defpath, - /* try_cwd */ true, }; static path_info pi_awklibpath = { /* envname */ "AWKLIBPATH", /* dfltp */ & deflibpath, - /* try_cwd */ false, }; /* init_awkpath --- split path(=$AWKPATH) into components */ @@ -2609,30 +2621,6 @@ init_awkpath(path_info *pi) #undef INC_PATH } -/* get_cwd -- get current working directory */ - -static char * -get_cwd () -{ -#define BSIZE 100 - char *buf; - size_t bsize = BSIZE; - - emalloc(buf, char *, bsize * sizeof(char), "get_cwd"); - while (true) { - if (getcwd(buf, bsize) == buf) - return buf; - if (errno != ERANGE) { - efree(buf); - return NULL; - } - bsize *= 2; - erealloc(buf, char *, bsize * sizeof(char), "get_cwd"); - } -#undef BSIZE -} - - /* do_find_source --- search $AWKPATH for file, return NULL if not found */ static char * @@ -2654,24 +2642,6 @@ do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi) return NULL; } - /* try current directory before $AWKPATH search */ - if (pi->try_cwd && stat(src, stb) == 0) { - path = get_cwd(); - if (path == NULL) { - *errcode = errno; - return NULL; - } - erealloc(path, char *, strlen(path) + strlen(src) + 2, "do_find_source"); -#ifdef VMS - if (strcspn(path,">]:") == strlen(path)) - strcat(path, "/"); -#else - strcat(path, "/"); -#endif - strcat(path, src); - return path; - } - if (pi->awkpath == NULL) init_awkpath(pi); diff --git a/m4/ChangeLog b/m4/ChangeLog index 81fdcec0..17c482cb 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,9 @@ +2014-10-30 Arnold D. Robbins <arnold@skeeve.com> + + * readline.m4: Enable cross compiling. Thanks to + Christer Solskogen <christer.solskogen@gmail.com> for + motivating and testing. + 2014-04-08 Arnold D. Robbins <arnold@skeeve.com> * 4.1.1: Release tar ball made. diff --git a/m4/readline.m4 b/m4/readline.m4 index 77ed8b25..740b9c7b 100644 --- a/m4/readline.m4 +++ b/m4/readline.m4 @@ -62,7 +62,28 @@ dnl action if true: dnl action if false: [_found_readline=no], dnl action if cross compiling: - [_found_readline=no] + AC_TRY_LINK([#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h>], dnl includes + dnl function body + [ + int fd; + char *line; + + close(0); + close(1); + fd = open("/dev/null", 2); /* should get fd 0 */ + dup(fd); + line = readline("giveittome> "); + + /* some printfs don't handle NULL for %s */ + printf("got <%s>\n", line ? line : "(NULL)"); +], +dnl action if found: + [_found_readline=yes], +dnl action if not found: + [_found_readline=no] + ) ) AC_MSG_RESULT([$_found_readline]) @@ -212,7 +212,7 @@ main(int argc, char **argv) /* * The + on the front tells GNU getopt not to rearrange argv. */ - const char *optlist = "+F:f:v:W;bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY"; + const char *optlist = "+F:f:v:W;bcCd::D::e:E:ghi:l:L:nNo::Op::MPrStVY"; bool stopped_early = false; int old_optind; int i; @@ -1066,18 +1066,23 @@ path_environ(const char *pname, const char *dflt) NODE *tmp; tmp = make_string(pname, strlen(pname)); - if (! in_array(ENVIRON_node, tmp)) { - /* - * On VMS, environ[] only holds a subset of what getenv() can - * find, so look AWKPATH up before resorting to default path. - */ - val = getenv(pname); - if (val == NULL) - val = dflt; - aptr = assoc_lookup(ENVIRON_node, tmp); + /* + * On VMS, environ[] only holds a subset of what getenv() can + * find, so look AWKPATH up before resorting to default path. + */ + val = getenv(pname); + if (val == NULL || *val == '\0') + val = dflt; + aptr = assoc_lookup(ENVIRON_node, tmp); + /* + * If original value was the empty string, set it to + * the default value. + */ + if ((*aptr)->stlen == 0) { unref(*aptr); *aptr = make_string(val, strlen(val)); } + unref(tmp); } @@ -1124,6 +1129,11 @@ load_environ() /* * Put AWKPATH and AWKLIBPATH into ENVIRON if not already there. * This allows querying it from within awk programs. + * + * October 2014: + * If their values are "", override with the default values; + * since 2.10 AWKPATH used default value if environment's + * value was "". */ path_environ("AWKPATH", defpath); path_environ("AWKLIBPATH", deflibpath); diff --git a/pc/ChangeLog b/pc/ChangeLog index a66edae9..235f520c 100644 --- a/pc/ChangeLog +++ b/pc/ChangeLog @@ -1,3 +1,7 @@ +2014-09-23 Scott Deifik <scottd.mail@sbcglobal.net> + + * Makefile.tst: Sync with mainline. + 2014-04-17 Scott Deifik <scottd.mail@sbcglobal.net> * Makefile.tst: Add readfile2 test. diff --git a/pc/Makefile.tst b/pc/Makefile.tst index 610704e4..48fc5189 100644 --- a/pc/Makefile.tst +++ b/pc/Makefile.tst @@ -180,19 +180,19 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \ backw badargs beginfile1 beginfile2 binmode1 charasbytes \ - colonwarn clos1way delsub devfd devfd1 devfd2 dumpvars exit \ + colonwarn clos1way dbugeval delsub devfd devfd1 devfd2 dumpvars exit \ fieldwdth fpat1 fpat2 fpat3 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectcall \ + include include2 indirectcall indirectcall2 \ lint lintold lintwarn \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ - patsplit posix printfbad1 printfbad2 printfbad3 procinfs \ + patsplit posix printfbad1 printfbad2 printfbad3 printhuge procinfs \ profile1 profile2 profile3 profile4 profile5 pty1 \ - rebuf regx8bit reginttrad reint reint2 rsstart1 \ + rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \ rsstart2 rsstart3 rstest6 shadow sortfor sortu split_after_fpat \ splitarg4 strftime \ strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ @@ -201,8 +201,9 @@ GAWK_EXT_TESTS = \ EXTRA_TESTS = inftest regtest INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat -MPFR_TESTS = mpfrnr mpfrnegzero mpfrrnd mpfrieee mpfrexprange \ - mpfrsort mpfrbigint +MPFR_TESTS = mpfrnr mpfrnegzero mpfrrem mpfrrnd mpfrieee mpfrexprange \ + mpfrsort mpfrsqrt mpfrbigint + LOCALE_CHARSET_TESTS = \ asort asorti backbigs1 backsmalls1 backsmalls2 \ fmttest fnarydel fnparydl jarebug lc_num1 mbfw1 \ @@ -318,6 +319,10 @@ machine-msg-end: charset-msg-start: @echo "======== Starting tests that can vary based on character set or locale support ========" + @echo "************************************************" + @echo "** Some or all of these tests may fail if you **" + @echo "** have inadequate or missing locale support **" + @echo "************************************************" charset-msg-end: @echo "======== Done with tests that can vary based on character set or locale support ========" @@ -352,7 +357,7 @@ poundbang:: @if ./_pbd.awk "$(srcdir)"/poundbang.awk > _`basename $@` ; \ then : ; \ else \ - sed "s;/tmp/gawk;../$(AWKPROG);" < "$(srcdir)"/poundbang.awk > ./_pbd.awk ; \ + sed "s;/tmp/gawk;$(AWKPROG);" < "$(srcdir)"/poundbang.awk > ./_pbd.awk ; \ chmod +x ./_pbd.awk ; \ LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} ./_pbd.awk "$(srcdir)"/poundbang.awk > _`basename $@`; \ fi @@ -503,6 +508,16 @@ fmtspcl: fmtspcl.ok $(CMP) "$(srcdir)"/$@-mpfr.ok _$@ && rm -f _$@ ; \ fi +rebuf:: + @echo $@ + @AWKBUFSIZE=4096 AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +rsglstdin:: + @echo $@ + @cat "$(srcdir)"/rsgetline.in | AWKPATH="$(srcdir)" $(AWK) -f rsgetline.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + reint:: @echo $@ @$(AWK) --re-interval -f "$(srcdir)"/reint.awk "$(srcdir)"/reint.in >_$@ @@ -932,6 +947,16 @@ mpfrbigint: @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mpfrsqrt: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +mpfrrem: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + jarebug:: @echo $@ @echo Expect jarebug to fail with DJGPP and MinGW. @@ -1135,6 +1160,22 @@ backsmalls2: @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \ AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +dbugeval:: + @echo $@ + @$(AWK) --debug -f /dev/null < "$(srcdir)"/$@.in > _$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +printhuge:: + @echo $@ + @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \ + AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +filefuncs: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk -v builddir="$(abs_top_builddir)" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ Gt-dummy: # file Maketests, generated from Makefile.am by the Gentests program addcomma: @@ -2227,6 +2268,11 @@ indirectcall: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +indirectcall2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lint: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2299,9 +2345,14 @@ pty1: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -rebuf: +regnul1: @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +regnul2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ regx8bit: @@ -2309,6 +2360,11 @@ regx8bit: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +rsgetline: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + rstest6: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2445,11 +2501,6 @@ fnmatch: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -filefuncs: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - fork: @echo $@ @echo Expect $@ to fail with MinGW because fork.dll is not available diff --git a/pc/config.h b/pc/config.h index c5d78a96..a6b2d4c4 100644 --- a/pc/config.h +++ b/pc/config.h @@ -242,6 +242,9 @@ #define HAVE_STDLIB_H 1 #endif +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 @@ -407,6 +410,9 @@ /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL +/* enable severe portability problems */ +#undef I_DONT_KNOW_WHAT_IM_DOING + /* libc is broken for regex handling */ #undef LIBC_IS_BORKED @@ -2,14 +2,14 @@ # Copyright (C) 2000 Free Software Foundation, Inc. # This file is distributed under the same license as the gawk package. # -# Philipp Thomas <pth@suse.de>, 2011 2012 +# Philipp Thomas <pth@suse.de>, 2011, 2012, 2014 # msgid "" msgstr "" -"Project-Id-Version: gawk 4.0.0h\n" +"Project-Id-Version: gawk 4.1.0b\n" "Report-Msgid-Bugs-To: arnold@skeeve.com\n" -"POT-Creation-Date: 2014-04-08 19:23+0300\n" -"PO-Revision-Date: 2012-01-30 16:21+0100\n" +"POT-Creation-Date: 2014-01-14 22:23+0200\n" +"PO-Revision-Date: 2014-10-23 17:31+0200\n" "Last-Translator: Philipp Thomas <pth@suse.de>\n" "Language-Team: German <translation-team-de@lists.sourceforge.net>\n" "Language: de\n" @@ -36,8 +36,8 @@ msgstr "Es wird versucht, den skalaren Parameter »%s« als Feld zu verwenden" msgid "attempt to use scalar `%s' as an array" msgstr "Es wird versucht, den Skalar »%s« als Array zu verwenden" -#: array.c:409 array.c:576 builtin.c:85 builtin.c:1615 builtin.c:1661 -#: builtin.c:1674 builtin.c:2102 builtin.c:2116 eval.c:1122 eval.c:1126 +#: array.c:409 array.c:576 builtin.c:85 builtin.c:1599 builtin.c:1645 +#: builtin.c:1658 builtin.c:2086 builtin.c:2100 eval.c:1122 eval.c:1126 #: eval.c:1531 #, c-format msgid "attempt to use array `%s' in a scalar context" @@ -54,9 +54,8 @@ msgid "attempt to use scalar `%s[\"%.*s\"]' as an array" msgstr "Es wird versucht, den Skalar »%s[\"%.*s\"]« als Feld zu verwenden" #: array.c:776 -#, fuzzy msgid "adump: first argument not an array" -msgstr "adump: Das Argument ist kein Feld" +msgstr "adump: Das erste Argument ist kein Feld" #: array.c:815 msgid "asort: second argument not an array" @@ -76,27 +75,19 @@ msgstr "asorti: Das erste Argument ist kein Feld" #: array.c:831 msgid "asort: cannot use a subarray of first arg for second arg" -msgstr "" -"asort: ein untergeordnetes Feld des ersten Arguments kann nicht als zweites " -"Argument verwendet werden" +msgstr "asort: ein untergeordnetes Feld des ersten Arguments kann nicht als zweites Argument verwendet werden" #: array.c:832 msgid "asorti: cannot use a subarray of first arg for second arg" -msgstr "" -"asorti: ein untergeordnetes Feld des ersten Arguments kann nicht als zweites " -"Argument verwendet werden" +msgstr "asorti: ein untergeordnetes Feld des ersten Arguments kann nicht als zweites Argument verwendet werden" #: array.c:837 msgid "asort: cannot use a subarray of second arg for first arg" -msgstr "" -"asort: ein untergeordnetes Feld des zweiten Arguments kann nicht als erstes " -"Argument verwendet werden" +msgstr "asort: ein untergeordnetes Feld des zweiten Arguments kann nicht als erstes Argument verwendet werden" #: array.c:838 msgid "asorti: cannot use a subarray of second arg for first arg" -msgstr "" -"asorti: ein untergeordnetes Feld des zweiten Arguments kann nicht als erstes " -"Argument verwendet werden" +msgstr "asorti: ein untergeordnetes Feld des zweiten Arguments kann nicht als erstes Argument verwendet werden" #: array.c:1314 #, c-format @@ -128,16 +119,12 @@ msgstr "»%s« ist eine eingebaute Funktion und kann nicht umdefiniert werden" #: awkgram.y:419 msgid "regexp constant `//' looks like a C++ comment, but is not" -msgstr "" -"Die Regulärer-Ausdruck-Konstante »//« sieht wie ein C-Kommentar aus, ist " -"aber keiner" +msgstr "Die Regulärer-Ausdruck-Konstante »//« sieht wie ein C-Kommentar aus, ist aber keiner" #: awkgram.y:423 #, c-format msgid "regexp constant `/%s/' looks like a C comment, but is not" -msgstr "" -"Die Regulärer-Ausdruck-Konstante »/%s/« sieht wie ein C-Kommentar aus, ist " -"aber keiner" +msgstr "Die Regulärer-Ausdruck-Konstante »/%s/« sieht wie ein C-Kommentar aus, ist aber keiner" #: awkgram.y:515 #, c-format @@ -148,12 +135,11 @@ msgstr "doppelte Case-Werte im Switch-Block: %s" msgid "duplicate `default' detected in switch body" msgstr "doppeltes »default« im Switch-Block gefunden" -#: awkgram.y:796 awkgram.y:3723 +#: awkgram.y:796 awkgram.y:3699 msgid "`break' is not allowed outside a loop or switch" -msgstr "" -"»break« ist außerhalb einer Schleife oder eines Switch-Blocks nicht zulässig" +msgstr "»break« ist außerhalb einer Schleife oder eines Switch-Blocks nicht zulässig" -#: awkgram.y:805 awkgram.y:3715 +#: awkgram.y:805 awkgram.y:3691 msgid "`continue' is not allowed outside a loop" msgstr "»continue« ist außerhalb einer Schleife nicht zulässig" @@ -173,16 +159,15 @@ msgstr "»return« wird außerhalb einer Funktion verwendet" #: awkgram.y:922 msgid "plain `print' in BEGIN or END rule should probably be `print \"\"'" -msgstr "" -"Einfaches »print« in BEGIN- oder END-Regel soll vermutlich »print \"\"« sein" +msgstr "Einfaches »print« in BEGIN- oder END-Regel soll vermutlich »print \"\"« sein" #: awkgram.y:988 awkgram.y:1037 msgid "`delete' is not allowed with SYMTAB" -msgstr "" +msgstr "»delete« ist in Zusammenhang mit SYMTAB nicht zulässig" #: awkgram.y:990 awkgram.y:1039 msgid "`delete' is not allowed with FUNCTAB" -msgstr "" +msgstr "»delete« ist in Zusammenhang mit FUNCTAB nicht zulässig" #: awkgram.y:1024 awkgram.y:1028 msgid "`delete(array)' is a non-portable tawk extension" @@ -220,8 +205,7 @@ msgstr "»getline« ist ungültig innerhalb der »%s«-Regel" #: awkgram.y:1425 msgid "non-redirected `getline' undefined inside END action" -msgstr "" -"Nicht-umgelenktes »getline« ist innerhalb der END-Aktion nicht definiert" +msgstr "Nicht-umgelenktes »getline« ist innerhalb der END-Aktion nicht definiert" #: awkgram.y:1444 msgid "old awk does not support multidimensional arrays" @@ -238,287 +222,274 @@ msgstr "indirekte Funktionsaufrufe sind eine gawk-Erweiterung" #: awkgram.y:1620 #, c-format msgid "can not use special variable `%s' for indirect function call" -msgstr "" -"die besondere Variable »%s« kann nicht für den indirekten Funktionsaufruf " -"verwendet werden" +msgstr "die besondere Variable »%s« kann nicht für den indirekten Funktionsaufruf verwendet werden" #: awkgram.y:1698 msgid "invalid subscript expression" msgstr "Ungültiger Index-Ausdruck" -#: awkgram.y:2048 awkgram.y:2068 gawkapi.c:206 gawkapi.c:224 msg.c:126 +#: awkgram.y:2024 awkgram.y:2044 gawkapi.c:206 gawkapi.c:224 msg.c:126 msgid "warning: " msgstr "Warnung: " -#: awkgram.y:2066 gawkapi.c:192 gawkapi.c:221 msg.c:158 +#: awkgram.y:2042 gawkapi.c:192 gawkapi.c:221 msg.c:158 msgid "fatal: " msgstr "Fatal: " -#: awkgram.y:2116 +#: awkgram.y:2092 msgid "unexpected newline or end of string" msgstr "Unerwarteter Zeilenumbruch oder Ende der Zeichenkette" -#: awkgram.y:2383 awkgram.y:2459 awkgram.y:2682 debug.c:523 debug.c:539 +#: awkgram.y:2359 awkgram.y:2435 awkgram.y:2658 debug.c:523 debug.c:539 #: debug.c:2812 debug.c:5055 #, c-format msgid "can't open source file `%s' for reading (%s)" msgstr "Quelldatei »%s« kann nicht zum Lesen geöffnet werden (%s)" -#: awkgram.y:2384 awkgram.y:2509 -#, fuzzy, c-format +#: awkgram.y:2360 awkgram.y:2485 +#, c-format msgid "can't open shared library `%s' for reading (%s)" -msgstr "Quelldatei »%s« kann nicht zum Lesen geöffnet werden (%s)" +msgstr "Die dynamische Bibliothek »%s« kann nicht zum Lesen geöffnet werden (%s)" -#: awkgram.y:2386 awkgram.y:2460 awkgram.y:2510 builtin.c:135 debug.c:5206 +#: awkgram.y:2362 awkgram.y:2436 awkgram.y:2486 builtin.c:135 debug.c:5206 msgid "reason unknown" msgstr "Unbekannte Ursache" -#: awkgram.y:2395 awkgram.y:2419 +#: awkgram.y:2371 awkgram.y:2395 #, c-format msgid "can't include `%s' and use it as a program file" -msgstr "" +msgstr "»%s« kann nicht eingebunden und als Programmdatei verwendet werden" -#: awkgram.y:2408 +#: awkgram.y:2384 #, c-format msgid "already included source file `%s'" msgstr "Quelldatei »%s« wurde bereits eingebunden" -#: awkgram.y:2409 -#, fuzzy, c-format +#: awkgram.y:2385 +#, c-format msgid "already loaded shared library `%s'" -msgstr "Quelldatei »%s« wurde bereits eingebunden" +msgstr "Die dynamische Bibliothek »%s« wurde bereits eingebunden" -#: awkgram.y:2444 +#: awkgram.y:2420 msgid "@include is a gawk extension" msgstr "»@include« ist eine gawk-Erweiterung" -#: awkgram.y:2450 +#: awkgram.y:2426 msgid "empty filename after @include" msgstr "leerer Dateiname nach @include" -#: awkgram.y:2494 -#, fuzzy +#: awkgram.y:2470 msgid "@load is a gawk extension" -msgstr "»@include« ist eine gawk-Erweiterung" +msgstr "»@load« ist eine Gawk-Erweiterung" -#: awkgram.y:2500 -#, fuzzy +#: awkgram.y:2476 msgid "empty filename after @load" -msgstr "leerer Dateiname nach @include" +msgstr "leerer Dateiname nach @load" -#: awkgram.y:2634 +#: awkgram.y:2610 msgid "empty program text on command line" msgstr "Kein Programmtext auf der Kommandozeile" -#: awkgram.y:2749 +#: awkgram.y:2725 #, c-format msgid "can't read sourcefile `%s' (%s)" msgstr "Die Quelldatei »%s« kann nicht gelesen werden (%s)" -#: awkgram.y:2760 +#: awkgram.y:2736 #, c-format msgid "source file `%s' is empty" msgstr "Die Quelldatei »%s« ist leer" -#: awkgram.y:2937 +#: awkgram.y:2913 msgid "source file does not end in newline" msgstr "Die Quelldatei hört nicht mit einem Zeilenende auf" -#: awkgram.y:3042 +#: awkgram.y:3018 msgid "unterminated regexp ends with `\\' at end of file" -msgstr "" -"Nicht beendeter regulärer Ausdruck (hört mit '\\' auf) am Ende der Datei" +msgstr "Nicht beendeter regulärer Ausdruck (hört mit '\\' auf) am Ende der Datei" -#: awkgram.y:3066 +#: awkgram.y:3042 #, c-format msgid "%s: %d: tawk regex modifier `/.../%c' doesn't work in gawk" -msgstr "" -"%s: %d: der tawk-Modifizierer für reguläre Ausdrücke »/.../%c« funktioniert " -"nicht in gawk" +msgstr "%s: %d: der tawk-Modifizierer für reguläre Ausdrücke »/.../%c« funktioniert nicht in gawk" -#: awkgram.y:3070 +#: awkgram.y:3046 #, c-format msgid "tawk regex modifier `/.../%c' doesn't work in gawk" -msgstr "" -"Der tawk-Modifizierer für reguläre Ausdrücke »/.../%c« funktioniert nicht in " -"gawk" +msgstr "Der tawk-Modifizierer für reguläre Ausdrücke »/.../%c« funktioniert nicht in gawk" -#: awkgram.y:3077 +#: awkgram.y:3053 msgid "unterminated regexp" msgstr "Nicht beendeter regulärer Ausdruck" -#: awkgram.y:3081 +#: awkgram.y:3057 msgid "unterminated regexp at end of file" msgstr "Nicht beendeter regulärer Ausdruck am Dateiende" -#: awkgram.y:3140 +#: awkgram.y:3116 msgid "use of `\\ #...' line continuation is not portable" -msgstr "" -"Die Verwendung von »\\#...« zur Fortsetzung von Zeilen ist nicht portabel" +msgstr "Die Verwendung von »\\#...« zur Fortsetzung von Zeilen ist nicht portabel" -#: awkgram.y:3156 +#: awkgram.y:3132 msgid "backslash not last character on line" msgstr "das letzte Zeichen auf der Zeile ist kein Backslash (»\\«)" -#: awkgram.y:3217 +#: awkgram.y:3193 msgid "POSIX does not allow operator `**='" msgstr "POSIX erlaubt den Operator »**=« nicht" -#: awkgram.y:3219 +#: awkgram.y:3195 msgid "old awk does not support operator `**='" msgstr "Das alte awk unterstützt den Operator »**=« nicht" -#: awkgram.y:3228 +#: awkgram.y:3204 msgid "POSIX does not allow operator `**'" msgstr "POSIX erlaubt den Operator »**« nicht" -#: awkgram.y:3230 +#: awkgram.y:3206 msgid "old awk does not support operator `**'" msgstr "Das alte awk unterstützt den Operator »**« nicht" -#: awkgram.y:3265 +#: awkgram.y:3241 msgid "operator `^=' is not supported in old awk" msgstr "Das alte awk unterstützt den Operator »^=« nicht" -#: awkgram.y:3273 +#: awkgram.y:3249 msgid "operator `^' is not supported in old awk" msgstr "Das alte awk unterstützt den Operator »^« nicht" -#: awkgram.y:3366 awkgram.y:3382 command.y:1178 +#: awkgram.y:3342 awkgram.y:3358 command.y:1178 msgid "unterminated string" msgstr "Nicht beendete Zeichenkette" -#: awkgram.y:3603 +#: awkgram.y:3579 #, c-format msgid "invalid char '%c' in expression" msgstr "Ungültiges Zeichen »%c« in einem Ausdruck" -#: awkgram.y:3650 +#: awkgram.y:3626 #, c-format msgid "`%s' is a gawk extension" msgstr "»%s« ist eine gawk-Erweiterung" -#: awkgram.y:3655 +#: awkgram.y:3631 #, c-format msgid "POSIX does not allow `%s'" msgstr "POSIX erlaubt »%s« nicht" -#: awkgram.y:3663 +#: awkgram.y:3639 #, c-format msgid "`%s' is not supported in old awk" msgstr "»%s« wird im alten awk nicht unterstützt" -#: awkgram.y:3753 +#: awkgram.y:3729 msgid "`goto' considered harmful!\n" msgstr "»goto« gilt als schlechter Stil!\n" -#: awkgram.y:3787 +#: awkgram.y:3763 #, c-format msgid "%d is invalid as number of arguments for %s" msgstr "Unzulässige Argumentzahl %d für %s" -#: awkgram.y:3822 +#: awkgram.y:3798 #, c-format msgid "%s: string literal as last arg of substitute has no effect" msgstr "%s: Ein String als letztes Argument von substitute hat keinen Effekt" -#: awkgram.y:3827 +#: awkgram.y:3803 #, c-format msgid "%s third parameter is not a changeable object" msgstr "Der dritte Parameter von %s ist ein unveränderliches Objekt" -#: awkgram.y:3910 awkgram.y:3913 +#: awkgram.y:3886 awkgram.y:3889 msgid "match: third argument is a gawk extension" msgstr "match: Das dritte Argument ist eine gawk-Erweiterung" -#: awkgram.y:3967 awkgram.y:3970 +#: awkgram.y:3943 awkgram.y:3946 msgid "close: second argument is a gawk extension" msgstr "close: Das zweite Argument ist eine gawk-Erweiterung" -#: awkgram.y:3982 +#: awkgram.y:3958 msgid "use of dcgettext(_\"...\") is incorrect: remove leading underscore" msgstr "" "Fehlerhafte Verwendung von dcgettext(_\"...\"): \n" "Entfernen Sie den führenden Unterstrich" -#: awkgram.y:3997 +#: awkgram.y:3973 msgid "use of dcngettext(_\"...\") is incorrect: remove leading underscore" msgstr "" "Fehlerhafte Verwendung von dcngettext(_\"...\"): \n" "Entfernen Sie den führenden Unterstrich" -#: awkgram.y:4016 -#, fuzzy +#: awkgram.y:3992 msgid "index: regexp constant as second argument is not allowed" -msgstr "index: Zweites Argument ist kein string" +msgstr "index: eine Regexp-Konstante als zweites Argument ist unzulässig" -#: awkgram.y:4069 +#: awkgram.y:4045 #, c-format msgid "function `%s': parameter `%s' shadows global variable" msgstr "Funktion »%s«: Parameter »%s« verdeckt eine globale Variable" -#: awkgram.y:4126 debug.c:4041 debug.c:4084 debug.c:5204 +#: awkgram.y:4102 debug.c:4041 debug.c:4084 debug.c:5204 #, c-format msgid "could not open `%s' for writing (%s)" msgstr "»%s« kann nicht zum Schreiben geöffne werden(%s)" -#: awkgram.y:4127 +#: awkgram.y:4103 msgid "sending variable list to standard error" msgstr "Die Liste der Variablen wird auf der Standardfehlerausgabe ausgegeben" -#: awkgram.y:4135 +#: awkgram.y:4111 #, c-format msgid "%s: close failed (%s)" msgstr "%s: close ist gescheitert (%s)" -#: awkgram.y:4160 +#: awkgram.y:4136 msgid "shadow_funcs() called twice!" msgstr "shadow_funcs() zweimal aufgerufen!" -#: awkgram.y:4168 +#: awkgram.y:4144 msgid "there were shadowed variables." msgstr "es sind verdeckte Variablen vorhanden" -#: awkgram.y:4239 +#: awkgram.y:4215 #, c-format msgid "function name `%s' previously defined" msgstr "Funktion »%s« wurde bereits definiert" -#: awkgram.y:4285 +#: awkgram.y:4261 #, c-format msgid "function `%s': can't use function name as parameter name" msgstr "Funktion »%s«: Funktionsnamen können nicht als Parameternamen benutzen" -#: awkgram.y:4288 +#: awkgram.y:4264 #, c-format msgid "function `%s': can't use special variable `%s' as a function parameter" -msgstr "" -"Funktion »%s«: die spezielle Variable »%s« kann nicht als Parameter " -"verwendet werden" +msgstr "Funktion »%s«: die spezielle Variable »%s« kann nicht als Parameter verwendet werden" -#: awkgram.y:4296 +#: awkgram.y:4272 #, c-format msgid "function `%s': parameter #%d, `%s', duplicates parameter #%d" msgstr "Funktion »%s«: Parameter #%d, »%s« wiederholt Parameter #%d" -#: awkgram.y:4383 awkgram.y:4389 +#: awkgram.y:4359 awkgram.y:4365 #, c-format msgid "function `%s' called but never defined" msgstr "Aufgerufene Funktion »%s« ist nirgends definiert" -#: awkgram.y:4393 +#: awkgram.y:4369 #, c-format msgid "function `%s' defined but never called directly" msgstr "Funktion »%s« wurde definiert aber nirgends aufgerufen" -#: awkgram.y:4425 +#: awkgram.y:4401 #, c-format msgid "regexp constant for parameter #%d yields boolean value" msgstr "" "Regulärer-Ausdruck-Konstante für Parameter #%d ergibt einen \n" "logischen Wert" -#: awkgram.y:4484 +#: awkgram.y:4460 #, c-format msgid "" "function `%s' called with space between name and `(',\n" @@ -527,24 +498,23 @@ msgstr "" "Funktion »%s« wird mit Leerzeichen zwischen Name und »(« aufgerufen, \n" "oder als Variable oder Feld verwendet" -#: awkgram.y:4720 +#: awkgram.y:4696 msgid "division by zero attempted" msgstr "Division durch Null wurde versucht" -#: awkgram.y:4729 +#: awkgram.y:4705 #, c-format msgid "division by zero attempted in `%%'" msgstr "Division durch Null versucht in »%%«" -#: awkgram.y:5049 -msgid "" -"cannot assign a value to the result of a field post-increment expression" -msgstr "" +#: awkgram.y:5025 +msgid "cannot assign a value to the result of a field post-increment expression" +msgstr "dem Ergebnis eines Feld-Postinkrementausdruck kann kein Wert zugewiesen werden" -#: awkgram.y:5052 -#, fuzzy, c-format +#: awkgram.y:5028 +#, c-format msgid "invalid target of assignment (opcode %s)" -msgstr "Unzulässige Argumentzahl %d für %s" +msgstr "Unzulässiges Ziel für eine Zuweisung (Opcode %s)" #: builtin.c:133 #, c-format @@ -567,15 +537,12 @@ msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" #: builtin.c:229 #, c-format msgid "fflush: cannot flush: pipe `%s' opened for reading, not writing" -msgstr "" -"fflush: Leeren der Puffer nicht möglich, Pipe »%s« ist nur zum Lesen geöffnet" +msgstr "fflush: Leeren der Puffer nicht möglich, Pipe »%s« ist nur zum Lesen geöffnet" #: builtin.c:232 #, c-format msgid "fflush: cannot flush: file `%s' opened for reading, not writing" -msgstr "" -"fflush: Leeren der Puffer nicht möglich, Datei »%s« ist nur zum Lesen " -"geöffnet" +msgstr "fflush: Leeren der Puffer nicht möglich, Datei »%s« ist nur zum Lesen geöffnet" #: builtin.c:244 #, c-format @@ -645,9 +612,7 @@ msgstr "Fatal: die Anzahl der Argumen bei »$« muss > 0 sein" #: builtin.c:919 #, c-format msgid "fatal: arg count %ld greater than total number of supplied arguments" -msgstr "" -"Fatal: Argumentenanzahl %ld ist größer als die Gesamtzahl angegebener " -"Argumente" +msgstr "Fatal: Argumentenanzahl %ld ist größer als die Gesamtzahl angegebener Argumente" #: builtin.c:923 msgid "fatal: `$' not permitted after period in format" @@ -658,315 +623,297 @@ msgid "fatal: no `$' supplied for positional field width or precision" msgstr "Fatal: »$« fehlt in positionsabhängiger Feldbreite oder Genauigkeit" # -#: builtin.c:1009 +#: builtin.c:1011 msgid "`l' is meaningless in awk formats; ignored" msgstr "»l« ist in awk-Formaten bedeutungslos, ignoriert" -#: builtin.c:1013 +#: builtin.c:1015 msgid "fatal: `l' is not permitted in POSIX awk formats" msgstr "Fatal: »l« ist in POSIX-awk-Formaten nicht zulässig" -#: builtin.c:1026 +#: builtin.c:1028 msgid "`L' is meaningless in awk formats; ignored" msgstr "»L« ist in awk-Formaten bedeutungslos, ignoriert" -#: builtin.c:1030 +#: builtin.c:1032 msgid "fatal: `L' is not permitted in POSIX awk formats" msgstr "Fatal: »L« ist in POSIX-awk-Formaten nicht zulässig" -#: builtin.c:1043 +#: builtin.c:1045 msgid "`h' is meaningless in awk formats; ignored" msgstr "»h« ist in awk-Formaten bedeutungslos, ignoriert" -#: builtin.c:1047 +#: builtin.c:1049 msgid "fatal: `h' is not permitted in POSIX awk formats" msgstr "Fatal: »h« ist in POSIX-awk-Formaten nicht zulässig" -#: builtin.c:1463 +#: builtin.c:1447 #, c-format msgid "[s]printf: value %g is out of range for `%%%c' format" msgstr "[s]printf: Wert %g ist außerhalb des Bereichs für Format »%%%c«" -#: builtin.c:1561 +#: builtin.c:1545 #, c-format msgid "ignoring unknown format specifier character `%c': no argument converted" -msgstr "" -"das unbekannte Zeichen »%c« in der Formatspezifikation wird ignoriert: keine " -"Argumente umgewandelt" +msgstr "das unbekannte Zeichen »%c« in der Formatspezifikation wird ignoriert: keine Argumente umgewandelt" -#: builtin.c:1566 +#: builtin.c:1550 msgid "fatal: not enough arguments to satisfy format string" msgstr "Fatal: Nicht genügend Argumente für die Formatangabe" -#: builtin.c:1568 +#: builtin.c:1552 msgid "^ ran out for this one" msgstr "^ hierfür fehlte es" -#: builtin.c:1575 +#: builtin.c:1559 msgid "[s]printf: format specifier does not have control letter" msgstr "[s]printf: Format-Spezifikation hat keinen Controlcode" -#: builtin.c:1578 +#: builtin.c:1562 msgid "too many arguments supplied for format string" msgstr "Zu viele Argumente für den Formatstring" -#: builtin.c:1634 -#, fuzzy +#: builtin.c:1618 msgid "sprintf: no arguments" -msgstr "printf: Keine Argumente" +msgstr "sprintf: Keine Argumente" -#: builtin.c:1657 builtin.c:1668 +#: builtin.c:1641 builtin.c:1652 msgid "printf: no arguments" msgstr "printf: Keine Argumente" -#: builtin.c:1711 +#: builtin.c:1695 msgid "sqrt: received non-numeric argument" msgstr "sqrt: das Argument ist keine Zahl" -#: builtin.c:1715 +#: builtin.c:1699 #, c-format msgid "sqrt: called with negative argument %g" msgstr "sqrt: das Argument %g ist negativ" -#: builtin.c:1746 +#: builtin.c:1730 #, c-format msgid "substr: length %g is not >= 1" msgstr "substr: Länge %g ist nicht >= 1" -#: builtin.c:1748 +#: builtin.c:1732 #, c-format msgid "substr: length %g is not >= 0" msgstr "substr: Länge %g ist nicht >= 0" -#: builtin.c:1755 +#: builtin.c:1739 #, c-format msgid "substr: non-integer length %g will be truncated" msgstr "substr: Nicht ganzzahlige Länge %g wird abgeschnitten" -#: builtin.c:1760 +#: builtin.c:1744 #, c-format msgid "substr: length %g too big for string indexing, truncating to %g" -msgstr "" -"substr: Länge %g ist zu groß für Stringindizierung, wird auf %g gekürzt" +msgstr "substr: Länge %g ist zu groß für Stringindizierung, wird auf %g gekürzt" -#: builtin.c:1772 +#: builtin.c:1756 #, c-format msgid "substr: start index %g is invalid, using 1" msgstr "substr: Start-Index %g ist ungültig, 1 wird verwendet" -#: builtin.c:1777 +#: builtin.c:1761 #, c-format msgid "substr: non-integer start index %g will be truncated" msgstr "substr: Nicht ganzzahliger Start-Wert %g wird abgeschnitten" -#: builtin.c:1802 +#: builtin.c:1786 msgid "substr: source string is zero length" msgstr "substr: Quellstring ist leer" -#: builtin.c:1818 +#: builtin.c:1802 #, c-format msgid "substr: start index %g is past end of string" msgstr "substr: Start-Wert %g liegt hinter dem Ende des Strings" -#: builtin.c:1826 +#: builtin.c:1810 #, c-format -msgid "" -"substr: length %g at start index %g exceeds length of first argument (%lu)" -msgstr "" -"substr: Länge %g am Start-Wert %g überschreitet die Länge des ersten " -"Arguments (%lu)" +msgid "substr: length %g at start index %g exceeds length of first argument (%lu)" +msgstr "substr: Länge %g am Start-Wert %g überschreitet die Länge des ersten Arguments (%lu)" -#: builtin.c:1900 +#: builtin.c:1884 msgid "strftime: format value in PROCINFO[\"strftime\"] has numeric type" msgstr "strftime: Formatwert in PROCINFO[\"strftime\"] ist numerischen Typs" -#: builtin.c:1923 +#: builtin.c:1907 msgid "strftime: received non-numeric second argument" msgstr "strftime: Das zweite Argument ist keine Zahl" -#: builtin.c:1927 +#: builtin.c:1911 msgid "strftime: second argument less than 0 or too big for time_t" -msgstr "" -"strftime: das zweite Argument ist kleiner als 0 oder zu groß für time_t" +msgstr "strftime: das zweite Argument ist kleiner als 0 oder zu groß für time_t" -#: builtin.c:1934 +#: builtin.c:1918 msgid "strftime: received non-string first argument" msgstr "strftime: Das erste Argument ist kein String" -#: builtin.c:1941 +#: builtin.c:1925 msgid "strftime: received empty format string" msgstr "strftime: Der Format-String ist leer" -#: builtin.c:2007 +#: builtin.c:1991 msgid "mktime: received non-string argument" msgstr "mktime: Das Argument ist kein String" -#: builtin.c:2024 +#: builtin.c:2008 msgid "mktime: at least one of the values is out of the default range" msgstr "mktime: mindestens einer der Werte ist außerhalb des normalen Bereichs" -#: builtin.c:2059 +#: builtin.c:2043 msgid "'system' function not allowed in sandbox mode" msgstr "Die Funktion »system« ist im Sandbox-Modus nicht erlaubt" -#: builtin.c:2064 +#: builtin.c:2048 msgid "system: received non-string argument" msgstr "system: Das Argument ist kein String" -#: builtin.c:2184 +#: builtin.c:2168 #, c-format msgid "reference to uninitialized field `$%d'" msgstr "Referenz auf das nicht initialisierte Feld »$%d«" -#: builtin.c:2271 +#: builtin.c:2255 msgid "tolower: received non-string argument" msgstr "tolower: das Argument ist kein String" -#: builtin.c:2305 +#: builtin.c:2289 msgid "toupper: received non-string argument" msgstr "toupper: das Argument ist kein String" -#: builtin.c:2341 mpfr.c:672 +#: builtin.c:2325 mpfr.c:672 msgid "atan2: received non-numeric first argument" msgstr "atan2: das erste Argument ist keine Zahl" -#: builtin.c:2343 mpfr.c:674 +#: builtin.c:2327 mpfr.c:674 msgid "atan2: received non-numeric second argument" msgstr "atan2: das zweite Argument ist keine Zahl" -#: builtin.c:2362 +#: builtin.c:2346 msgid "sin: received non-numeric argument" msgstr "sin: das Argument ist keine Zahl" -#: builtin.c:2378 +#: builtin.c:2362 msgid "cos: received non-numeric argument" msgstr "cos: das Argument ist keine Zahl" -#: builtin.c:2431 mpfr.c:1156 +#: builtin.c:2415 mpfr.c:1156 msgid "srand: received non-numeric argument" msgstr "srand: das Argument ist keine Zahl" -#: builtin.c:2462 +#: builtin.c:2446 msgid "match: third argument is not an array" msgstr "match: das dritte Argument ist kein Array" -#: builtin.c:2734 +#: builtin.c:2718 msgid "gensub: third argument of 0 treated as 1" msgstr "gensub: 0 als drittes Argument wird als 1 interpretiert" -#: builtin.c:3030 +#: builtin.c:3014 msgid "lshift: received non-numeric first argument" msgstr "lshift: das erste Argument ist keine Zahl" -#: builtin.c:3032 +#: builtin.c:3016 msgid "lshift: received non-numeric second argument" msgstr "lshift: das zweite Argument ist keine Zahl" -#: builtin.c:3038 -#, fuzzy, c-format +#: builtin.c:3022 +#, c-format msgid "lshift(%f, %f): negative values will give strange results" -msgstr "" -"lshift(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" +msgstr "lshift(%f, %f): Negative Werte werden zu merkwürdigen Ergebnissen führen" -#: builtin.c:3040 -#, fuzzy, c-format +#: builtin.c:3024 +#, c-format msgid "lshift(%f, %f): fractional values will be truncated" -msgstr "lshift(%lf, %lf): Dezimalteil wird abgeschnitten" +msgstr "lshift(%f, %f): Dezimalteil wird abgeschnitten" -#: builtin.c:3042 -#, fuzzy, c-format +#: builtin.c:3026 +#, c-format msgid "lshift(%f, %f): too large shift value will give strange results" -msgstr "" -"lshift(%lf, %lf): Zu große Shift-Werte werden zu merkwürdigen Ergebnissen " -"führen" +msgstr "lshift(%f, %f): Zu große Shift-Werte werden zu merkwürdigen Ergebnissen führen" -#: builtin.c:3067 +#: builtin.c:3051 msgid "rshift: received non-numeric first argument" msgstr "rshift: das erste Argument ist keine Zahl" -#: builtin.c:3069 +#: builtin.c:3053 msgid "rshift: received non-numeric second argument" msgstr "rshift: das zweite Argument ist keine Zahl" -#: builtin.c:3075 -#, fuzzy, c-format +#: builtin.c:3059 +#, c-format msgid "rshift(%f, %f): negative values will give strange results" -msgstr "" -"rshift (%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" +msgstr "rshift (%f, %f): Negative Werte werden zu merkwürdigen Ergebnissen führen" -#: builtin.c:3077 -#, fuzzy, c-format +#: builtin.c:3061 +#, c-format msgid "rshift(%f, %f): fractional values will be truncated" -msgstr "rshift(%lf, %lf): Dezimalteil wird abgeschnitten" +msgstr "rshift(%f, %f): Dezimalteil wird abgeschnitten" -#: builtin.c:3079 -#, fuzzy, c-format +#: builtin.c:3063 +#, c-format msgid "rshift(%f, %f): too large shift value will give strange results" -msgstr "" -"rshift(%lf, %lf): Zu große Shift-Werte werden zu merkwürdigen Ergebnissen " -"führen" +msgstr "rshift(%f, %f): Zu große Shift-Werte werden zu merkwürdigen Ergebnissen führen" -#: builtin.c:3104 mpfr.c:968 -#, fuzzy +#: builtin.c:3088 mpfr.c:968 msgid "and: called with less than two arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "and: wird mit weniger als zwei Argumenten aufgerufen" -#: builtin.c:3109 -#, fuzzy, c-format +#: builtin.c:3093 +#, c-format msgid "and: argument %d is non-numeric" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "and: das Argument %d ist nicht numerisch" -#: builtin.c:3113 -#, fuzzy, c-format +#: builtin.c:3097 +#, c-format msgid "and: argument %d negative value %g will give strange results" -msgstr "" -"and(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" +msgstr "and: der negative Wert %2$g von Argument %1$d wird zu merkwürdigen Ergebnissen führen" -#: builtin.c:3136 mpfr.c:1000 -#, fuzzy +#: builtin.c:3120 mpfr.c:1000 msgid "or: called with less than two arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "or: wird mit weniger als zwei Argumenten aufgerufen" -#: builtin.c:3141 -#, fuzzy, c-format +#: builtin.c:3125 +#, c-format msgid "or: argument %d is non-numeric" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "or: das Argument %d ist nicht numerisch" -#: builtin.c:3145 -#, fuzzy, c-format +#: builtin.c:3129 +#, c-format msgid "or: argument %d negative value %g will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "or: der negative Wert %2$g von Argument %1$d wird zu merkwürdigen Ergebnissen führen" -#: builtin.c:3167 mpfr.c:1031 -#, fuzzy +#: builtin.c:3151 mpfr.c:1031 msgid "xor: called with less than two arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "xor: wird mit weniger als zwei Argumenten aufgerufen" -#: builtin.c:3173 -#, fuzzy, c-format +#: builtin.c:3157 +#, c-format msgid "xor: argument %d is non-numeric" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "xor: das Argument %d ist nicht numerisch" -#: builtin.c:3177 -#, fuzzy, c-format +#: builtin.c:3161 +#, c-format msgid "xor: argument %d negative value %g will give strange results" -msgstr "xor(%lf, %lf: Negative Werte werden zu merkwürdigen Ergebnissen führen" +msgstr "xor: der negative Wert %2$g von Argument %1$d wird zu merkwürdigen Ergebnissen führen" -#: builtin.c:3202 mpfr.c:787 +#: builtin.c:3186 mpfr.c:787 msgid "compl: received non-numeric argument" msgstr "compl: das erste Argument ist keine Zahl" -#: builtin.c:3208 -#, fuzzy, c-format +#: builtin.c:3192 +#, c-format msgid "compl(%f): negative value will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "compl(%f): Der negative Wert wird zu merkwürdigen Ergebnissen führen" -#: builtin.c:3210 -#, fuzzy, c-format +#: builtin.c:3194 +#, c-format msgid "compl(%f): fractional value will be truncated" -msgstr "compl(%lf): Dezimalteil wird abgeschnitten" +msgstr "compl(%f): der Dezimalteil wird abgeschnitten" -#: builtin.c:3379 +#: builtin.c:3363 #, c-format msgid "dcgettext: `%s' is not a valid locale category" msgstr "dcgettext: »%s« ist keine gültige Locale-Kategorie" @@ -974,279 +921,266 @@ msgstr "dcgettext: »%s« ist keine gültige Locale-Kategorie" #: command.y:225 #, c-format msgid "Type (g)awk statement(s). End with the command \"end\"\n" -msgstr "" +msgstr "Geben Sie »(g)awk Ausdrücke« und zum Abschluss \"end\" ein\n" #: command.y:289 -#, fuzzy, c-format +#, c-format msgid "invalid frame number: %d" -msgstr "Ungültiges Bereichsende" +msgstr "Ungültige Frame-Nummer: %d" #: command.y:295 -#, fuzzy, c-format +#, c-format msgid "info: invalid option - \"%s\"" -msgstr "%s: Ungültige Option -- »%c«\n" +msgstr "info: Ungültige Option - »%s«" #: command.y:321 #, c-format msgid "source \"%s\": already sourced." -msgstr "" +msgstr "Quelle »%s«: wurde bereits eingelesen." #: command.y:326 #, c-format msgid "save \"%s\": command not permitted." -msgstr "" +msgstr "save »%s«: Der Befehl ist nicht zulässig." #: command.y:339 msgid "Can't use command `commands' for breakpoint/watchpoint commands" -msgstr "" +msgstr "Der Befehl »commands« kann nicht für Break- bzw. Watchpoints verwendet werden" #: command.y:341 msgid "no breakpoint/watchpoint has been set yet" -msgstr "" +msgstr "es wurden noch keine Break-/Watchpoints gesetzt" #: command.y:343 msgid "invalid breakpoint/watchpoint number" -msgstr "" +msgstr "ungültige Break-/Watchpoint/Nummer" #: command.y:348 #, c-format msgid "Type commands for when %s %d is hit, one per line.\n" -msgstr "" +msgstr "Befehle eingeben, die bei Erreichen von %s %d ausgeführt werden sollen, einer pro Zeile.\n" #: command.y:350 #, c-format msgid "End with the command \"end\"\n" -msgstr "" +msgstr "Abschließen mit dem Befehl »end«\n" #: command.y:357 msgid "`end' valid only in command `commands' or `eval'" -msgstr "" +msgstr "»end« ist nur innerhalb der Befehle »commands« oder »eval« zulässig" #: command.y:367 msgid "`silent' valid only in command `commands'" -msgstr "" +msgstr "»silent« ist nur innerhalb des Befehls »commands« zuzlässig" #: command.y:373 -#, fuzzy, c-format +#, c-format msgid "trace: invalid option - \"%s\"" -msgstr "%s: Ungültige Option -- »%c«\n" +msgstr "trace: Ungültige Option - »%s«" #: command.y:387 msgid "condition: invalid breakpoint/watchpoint number" -msgstr "" +msgstr "condition: Unzulässige Break-/Watchpoint-Nummer" #: command.y:449 -#, fuzzy msgid "argument not a string" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "Das Argument ist keine Zeichenkette" #: command.y:459 command.y:464 #, c-format msgid "option: invalid parameter - \"%s\"" -msgstr "" +msgstr "option: ungültiger Parameter - »%s«" #: command.y:474 #, c-format msgid "no such function - \"%s\"" -msgstr "" +msgstr "Unbekannte Funktion - »%s«" #: command.y:531 -#, fuzzy, c-format +#, c-format msgid "enable: invalid option - \"%s\"" -msgstr "%s: Ungültige Option -- »%c«\n" +msgstr "enable: Ungültige Option - »%s«" #: command.y:597 -#, fuzzy, c-format +#, c-format msgid "invalid range specification: %d - %d" -msgstr "Ungültiges Bereichsende" +msgstr "Ungültige Bereichsangabe: %d - %d" #: command.y:659 -#, fuzzy msgid "non-numeric value for field number" -msgstr "unbekannter Wert für eine Feldangabe: %d\n" +msgstr "nichtnumerischer Wert als Feldnummer" #: command.y:680 command.y:687 msgid "non-numeric value found, numeric expected" -msgstr "" +msgstr "nichtnumerischer Wert wo ein numerischer erwartet wurde" #: command.y:712 command.y:718 msgid "non-zero integer value" -msgstr "" +msgstr "ganyzahliger Wert ungleich Null" #: command.y:817 -msgid "" -"backtrace [N] - print trace of all or N innermost (outermost if N < 0) " -"frames." -msgstr "" +msgid "backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames." +msgstr "backtrace [N] - log von allen oder den N innersten (äußersten wenn N < 0) Rahmen." #: command.y:819 -msgid "" -"break [[filename:]N|function] - set breakpoint at the specified location." -msgstr "" +msgid "break [[filename:]N|function] - set breakpoint at the specified location." +msgstr "break [[Dateiname:]N|funktion - Breakpoint an der angegebenen Stelle setzen.]" #: command.y:821 msgid "clear [[filename:]N|function] - delete breakpoints previously set." -msgstr "" +msgstr "clear [[Dateiname:]N|Funktion - zuvor gesetzte Breakpoints löschen." #: command.y:823 -msgid "" -"commands [num] - starts a list of commands to be executed at a " -"breakpoint(watchpoint) hit." -msgstr "" +msgid "commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit." +msgstr "commands [Nr] - startet eine Liste von Befehlen, die bei Erreichen eines Break- bzw. Watchpoints ausgeführt werden." #: command.y:825 msgid "condition num [expr] - set or clear breakpoint or watchpoint condition." -msgstr "" +msgstr "condition Nr [Ausdruck] - Bedingungen für einen Break-/Watchpoint setzen oder löschen." #: command.y:827 msgid "continue [COUNT] - continue program being debugged." -msgstr "" +msgstr "continue [ANZAHL] - zu debuggendes Programm fortsetzen." #: command.y:829 msgid "delete [breakpoints] [range] - delete specified breakpoints." -msgstr "" +msgstr "delete [Breakpoints] [Bereich] - angegebene Breakpoints entfernen." #: command.y:831 msgid "disable [breakpoints] [range] - disable specified breakpoints." -msgstr "" +msgstr "disable [Breakpoints] [Bereich] - angegebene Breakpoints deaktivieren." #: command.y:833 msgid "display [var] - print value of variable each time the program stops." -msgstr "" +msgstr "display [Var] - den Wert der Variablen bei jedem Programmstop ausgeben." #: command.y:835 msgid "down [N] - move N frames down the stack." -msgstr "" +msgstr "down [N] - N Rahmen nach unten im Stack gehen." #: command.y:837 msgid "dump [filename] - dump instructions to file or stdout." -msgstr "" +msgstr "dump [Dateiname] - Befehle in eine Datei oder auf der Standardausgabe ausgeben" #: command.y:839 msgid "enable [once|del] [breakpoints] [range] - enable specified breakpoints." -msgstr "" +msgstr "enable [once|del] [Breakpoints] [Bereich] - die angegebenen Breakpoints aktivieren." #: command.y:841 msgid "end - end a list of commands or awk statements." -msgstr "" +msgstr "end - beendet eine Liste von Befehlen oder AWK/Ausdrücken." #: command.y:843 msgid "eval stmt|[p1, p2, ...] - evaluate awk statement(s)." -msgstr "" +msgstr "eval stmt[p1, p2, ...] - Awk-Ausdrücke auswerten." #: command.y:845 msgid "finish - execute until selected stack frame returns." -msgstr "" +msgstr "finish - mit Ausführung fortfahren bis auisgewählter Rahmen verlassen wird." #: command.y:847 msgid "frame [N] - select and print stack frame number N." -msgstr "" +msgstr "frame [N] - den Stackrahmen Nummer N auswählen und ausgeben." #: command.y:849 msgid "help [command] - print list of commands or explanation of command." -msgstr "" +msgstr "help [Befehl] - gibt eine Liste der Befehle oder die Beschreibung eines einzelnen Befehls aus." #: command.y:851 msgid "ignore N COUNT - set ignore-count of breakpoint number N to COUNT." -msgstr "" +msgstr "ignore N ZÄHLER - setzt den Ignorieren-Zähler von Breakpoint N auf ZÄHLER" #: command.y:853 -msgid "" -"info topic - source|sources|variables|functions|break|frame|args|locals|" -"display|watch." -msgstr "" +msgid "info topic - source|sources|variables|functions|break|frame|args|locals|display|watch." +msgstr "info Thema - source|sources|variables|functions|break|frame|args|locals|display|watch." #: command.y:855 msgid "list [-|+|[filename:]lineno|function|range] - list specified line(s)." -msgstr "" +msgstr "list [-|+|[Dateiname:]Zeilennr|Funktion|Breich] - die angegebenen Zeilen ausgeben" #: command.y:857 msgid "next [COUNT] - step program, proceeding through subroutine calls." -msgstr "" +msgstr "next [ZÄHLER] - Programm schrittweise ausführen aber Subroutinen in einem Rutsch ausführen" #: command.y:859 -msgid "" -"nexti [COUNT] - step one instruction, but proceed through subroutine calls." -msgstr "" +msgid "nexti [COUNT] - step one instruction, but proceed through subroutine calls." +msgstr "nexti [ZÄHLER] - einen Befehl abarbeiten. aber Subroutinen in einem Rutsch ausführen" #: command.y:861 msgid "option [name[=value]] - set or display debugger option(s)." -msgstr "" +msgstr "option [Name[=Wer]] - Debuggeroptionen setzen oder anzeigen." #: command.y:863 msgid "print var [var] - print value of a variable or array." -msgstr "" +msgstr "print Var [Var] - den Wert einer Variablen oder eines Feldes ausgeben." #: command.y:865 msgid "printf format, [arg], ... - formatted output." -msgstr "" +msgstr "printf Format, [Arg], ... - formatierte Ausgabe." #: command.y:867 msgid "quit - exit debugger." -msgstr "" +msgstr "quit - Debugger verlassen" #: command.y:869 msgid "return [value] - make selected stack frame return to its caller." -msgstr "" +msgstr "return [Wert] - den ausgewählten Stapelrahmen yu seinem Aufrufer zurück kehren lassen" #: command.y:871 msgid "run - start or restart executing program." -msgstr "" +msgstr "run - startet die (erneute) Ausführung des Programms." #: command.y:874 msgid "save filename - save commands from the session to file." -msgstr "" +msgstr "save Dateineme - sichert die Befehle der Sitzung in einer Datei." #: command.y:877 msgid "set var = value - assign value to a scalar variable." -msgstr "" +msgstr "set Var = Wert - einer skalaren Variablen einen Wert zuweisen" #: command.y:879 -msgid "" -"silent - suspends usual message when stopped at a breakpoint/watchpoint." -msgstr "" +msgid "silent - suspends usual message when stopped at a breakpoint/watchpoint." +msgstr "silent - unterdrückt die übliche Nachricht, wenn ein Break- bzw. Watchpoint erreicht wird." #: command.y:881 msgid "source file - execute commands from file." -msgstr "" +msgstr "source Datei - die Befehle in Datei ausführen" #: command.y:883 msgid "step [COUNT] - step program until it reaches a different source line." -msgstr "" +msgstr "step [ZÄHLER - Programm schrittweise ausführen bis es eine andere Quellzeile erricht." #: command.y:885 msgid "stepi [COUNT] - step one instruction exactly." -msgstr "" +msgstr "stepi [ZÄHLER - genau eine Instruktion ausführen" #: command.y:887 msgid "tbreak [[filename:]N|function] - set a temporary breakpoint." -msgstr "" +msgstr "tbreak [[Dateinem:]N|Funktion] - einen temporären Breakpoint setzen." #: command.y:889 msgid "trace on|off - print instruction before executing." -msgstr "" +msgstr "trace on|off - Instruktionen vor der Ausführung ausgeben." #: command.y:891 msgid "undisplay [N] - remove variable(s) from automatic display list." -msgstr "" +msgstr "undisplay [N] - Variablen von der Liste der automatisch Anzuzeigenden entfernen." #: command.y:893 -msgid "" -"until [[filename:]N|function] - execute until program reaches a different " -"line or line N within current frame." -msgstr "" +msgid "until [[filename:]N|function] - execute until program reaches a different line or line N within current frame." +msgstr "until [[Dateiname:]N|Funktion - Ausführen bis das Programm eine andere Zeile erreicht oder N Zeilen im aktuellen Rahmen." #: command.y:895 msgid "unwatch [N] - remove variable(s) from watch list." -msgstr "" +msgstr "unwatch [N} - Variablen von der Beobachtungsliste löschen" #: command.y:897 msgid "up [N] - move N frames up the stack." -msgstr "" +msgstr "up [N] - N Rahmen im Kellerspeicher nach oben gehen." #: command.y:899 msgid "watch var - set a watchpoint for a variable." -msgstr "" +msgstr "watch Var - einen Watchpoint für eine Variable setzen." #: command.y:1011 debug.c:401 msg.c:135 #, c-format @@ -1254,594 +1188,596 @@ msgid "error: " msgstr "Fehler: " #: command.y:1051 -#, fuzzy, c-format +#, c-format msgid "can't read command (%s)\n" -msgstr "Von »%s« kann nicht umgelenkt werden (%s)" +msgstr "der Befehl kann nicht gelesen werden (»%s«)\n" #: command.y:1065 -#, fuzzy, c-format +#, c-format msgid "can't read command (%s)" -msgstr "Von »%s« kann nicht umgelenkt werden (%s)" +msgstr "der Befehl kann nicht gelesen werden (»%s«)" #: command.y:1116 -#, fuzzy msgid "invalid character in command" -msgstr "Ungültiger Name für eine Zeichenklasse" +msgstr "Ungültiges Zeichen im Befehl" #: command.y:1152 #, c-format msgid "unknown command - \"%.*s\", try help" -msgstr "" +msgstr "unbekannter Befehl - »%.*s«, versuchen Sie es mit help" #: command.y:1222 #, c-format msgid "%s" -msgstr "" +msgstr "%s" #: command.y:1284 -#, fuzzy msgid "invalid character" msgstr "Ungültiges Zeichen" #: command.y:1455 #, c-format msgid "undefined command: %s\n" -msgstr "" +msgstr "undefinierter Befehl: %s\n" #: debug.c:252 msgid "set or show the number of lines to keep in history file." -msgstr "" +msgstr "die Anzahl von Zeilen setzen oder anzeigen, die in der Historydatei gespeichert werden sollen." #: debug.c:254 msgid "set or show the list command window size." -msgstr "" +msgstr "die Größe des Fensters für den Befehl list setzen oder anzeigen." #: debug.c:256 msgid "set or show gawk output file." -msgstr "" +msgstr "die gawk Ausgabedatei setzen oder anzeigen." #: debug.c:258 msgid "set or show debugger prompt." -msgstr "" +msgstr "das Debugger-Prompt setzen oder anzeigen." #: debug.c:260 msgid "(un)set or show saving of command history (value=on|off)." -msgstr "" +msgstr "(rück)setzen des Sicherns der Befehlshistorie (on oder off)." #: debug.c:262 msgid "(un)set or show saving of options (value=on|off)." -msgstr "" +msgstr "(rück)setzen des Sicherns von Optionen (on oder off)." #: debug.c:264 msgid "(un)set or show instruction tracing (value=on|off)." -msgstr "" +msgstr "(rück)setzen des Verfolgens von Instruktionen (on oder off)." #: debug.c:345 msgid "program not running." -msgstr "" +msgstr "Das Programm läuft nicht." #: debug.c:448 debug.c:606 -#, fuzzy, c-format +#, c-format msgid "can't read source file `%s' (%s)" msgstr "Die Quelldatei »%s« kann nicht gelesen werden (%s)" #: debug.c:453 -#, fuzzy, c-format +#, c-format msgid "source file `%s' is empty.\n" -msgstr "Die Quelldatei »%s« ist leer" +msgstr "Die Quelldatei »%s« ist leer.\n" #: debug.c:480 msgid "no current source file." -msgstr "" +msgstr "keine aktuelle Quelldatei" #: debug.c:505 -#, fuzzy, c-format +#, c-format msgid "cannot find source file named `%s' (%s)" -msgstr "Die Quelldatei »%s« kann nicht gelesen werden (%s)" +msgstr "Die Quelldatei »%s« kann nicht gefunden werden (%s)" #: debug.c:529 #, c-format msgid "WARNING: source file `%s' modified since program compilation.\n" -msgstr "" +msgstr "WARNUNG: Quelldatei »%s« wurde seit der Programmübersetzung verändert.\n" #: debug.c:551 #, c-format msgid "line number %d out of range; `%s' has %d lines" -msgstr "" +msgstr "die Zeilennummer %d ist außerhalb des gültigen Bereichs: »%s« hat %d Zeilen" #: debug.c:611 -#, fuzzy, c-format +#, c-format msgid "unexpected eof while reading file `%s', line %d" -msgstr "Unerwarteter Zeilenumbruch oder Ende der Zeichenkette" +msgstr "Unerwartetes Dateiende beim Lesen von Datei »%s<<, Zeile %d" #: debug.c:620 #, c-format msgid "source file `%s' modified since start of program execution" -msgstr "" +msgstr "Quelldatei »%s« wurde seit dem Start des Programmes verändert" #: debug.c:732 -#, fuzzy, c-format +#, c-format msgid "Current source file: %s\n" -msgstr "Quelldatei »%s« wurde bereits eingebunden" +msgstr "Derzeitige Quelldatei: %s\n" #: debug.c:733 #, c-format msgid "Number of lines: %d\n" -msgstr "" +msgstr "Anzahl von Zeilen: %d\n" #: debug.c:740 #, c-format msgid "Source file (lines): %s (%d)\n" -msgstr "" +msgstr "Quelldatei (Zeilen): %s (%d)\n" #: debug.c:754 msgid "" "Number Disp Enabled Location\n" "\n" msgstr "" +"Nummer Anz. Aktiv Ort\n" +"\n" #: debug.c:765 #, c-format msgid "\tno of hits = %ld\n" -msgstr "" +msgstr "\tAnzahl Treffer = %ld\n" #: debug.c:767 #, c-format msgid "\tignore next %ld hit(s)\n" -msgstr "" +msgstr "\tdie nächsten %ld Treffer\n" #: debug.c:769 debug.c:909 #, c-format msgid "\tstop condition: %s\n" -msgstr "" +msgstr "\tStopbedingung: %s\n" #: debug.c:771 debug.c:911 msgid "\tcommands:\n" -msgstr "" +msgstr "\tBefehle:\n" #: debug.c:793 #, c-format msgid "Current frame: " -msgstr "" +msgstr "Derzeitiger Stapelrahmen" #: debug.c:796 #, c-format msgid "Called by frame: " -msgstr "" +msgstr "Aufgerufen aus Rahmen: " #: debug.c:800 #, c-format msgid "Caller of frame: " -msgstr "" +msgstr "Aufrufer des Rahmens: " #: debug.c:818 #, c-format msgid "None in main().\n" -msgstr "" +msgstr "Keine in main().\n" #: debug.c:848 -#, fuzzy msgid "No arguments.\n" -msgstr "printf: Keine Argumente" +msgstr "Keine Argumente.\n" #: debug.c:849 msgid "No locals.\n" -msgstr "" +msgstr "Keine lokalen.\n" #: debug.c:857 msgid "" "All defined variables:\n" "\n" msgstr "" +"Alle definierten Variablen:\n" +"\n" #: debug.c:867 msgid "" "All defined functions:\n" "\n" msgstr "" +"Alle definierten Funktionen:\n" +"\n" #: debug.c:886 msgid "" "Auto-display variables:\n" "\n" msgstr "" +"Auto-display-Variablen:\n" +"\n" #: debug.c:889 msgid "" "Watch variables:\n" "\n" msgstr "" +"Yu überwachende Variablen:\n" +"\n" #: debug.c:1029 -#, fuzzy, c-format +#, c-format msgid "no symbol `%s' in current context\n" -msgstr "»exit« kann im aktuellen Kontext nicht aufgerufen werden" +msgstr "im aktuellen Kontext gibt es kein Symbol mit Namen »%s«\n" #: debug.c:1041 debug.c:1427 -#, fuzzy, c-format +#, c-format msgid "`%s' is not an array\n" -msgstr "»%s« ist kein gültiger Variablenname" +msgstr "»%s« ist kein Feld\n" #: debug.c:1055 -#, fuzzy, c-format +#, c-format msgid "$%ld = uninitialized field\n" -msgstr "Referenz auf das nicht initialisierte Feld »$%d«" +msgstr "$%ld = nicht initialisiertes Feld\n" #: debug.c:1076 -#, fuzzy, c-format +#, c-format msgid "array `%s' is empty\n" -msgstr "Die Datei »%s« ist leer" +msgstr "Das Feld »%s« ist leer\n" #: debug.c:1119 debug.c:1171 -#, fuzzy, c-format +#, c-format msgid "[\"%s\"] not in array `%s'\n" -msgstr "delete: Index »%s« ist in Feld »%s« nicht vorhanden" +msgstr "[\"%s\"] ist in Feld »%s« nicht vorhanden\n" #: debug.c:1175 #, c-format msgid "`%s[\"%s\"]' is not an array\n" -msgstr "" +msgstr "»%s[\"%s\"]« ist kein Feld\n" #: debug.c:1236 debug.c:4964 -#, fuzzy, c-format +#, c-format msgid "`%s' is not a scalar variable" -msgstr "»%s« ist kein gültiger Variablenname" +msgstr "»%s« ist keine skalare Variable" #: debug.c:1258 debug.c:4994 -#, fuzzy, c-format +#, c-format msgid "attempt to use array `%s[\"%s\"]' in a scalar context" -msgstr "" -"Es wird versucht, das Feld »%s[\"%.*s\"]« in einem Skalarkontext zu verwenden" +msgstr "Es wird versucht, das Feld »%s[\"%s\"]« in einem Skalarkontext zu verwenden" #: debug.c:1280 debug.c:5005 -#, fuzzy, c-format +#, c-format msgid "attempt to use scalar `%s[\"%s\"]' as array" -msgstr "Es wird versucht, den Skalar »%s[\"%.*s\"]« als Feld zu verwenden" +msgstr "Es wird versucht, den Skalar »%s[\"%s\"]« als Feld zu verwenden" #: debug.c:1423 -#, fuzzy, c-format +#, c-format msgid "`%s' is a function" -msgstr "»%s« ist ein unzulässiger Funktionsname" +msgstr "»%s« ist eine Funktion" #: debug.c:1465 #, c-format msgid "watchpoint %d is unconditional\n" -msgstr "" +msgstr "Watchpoint %d ist bedingungslos\n" #: debug.c:1499 #, c-format msgid "No display item numbered %ld" -msgstr "" +msgstr "Kein anzuzeigendes Element mit Nummer %ld" #: debug.c:1502 #, c-format msgid "No watch item numbered %ld" -msgstr "" +msgstr "Kein zu beobachtendes Element mit Nummer %ld" #: debug.c:1528 -#, fuzzy, c-format +#, c-format msgid "%d: [\"%s\"] not in array `%s'\n" -msgstr "delete: Index »%s« ist in Feld »%s« nicht vorhanden" +msgstr "%d: [\"%s\"] ist in Feld »%s« nicht vorhanden\n" #: debug.c:1767 -#, fuzzy msgid "attempt to use scalar value as array" msgstr "Es wird versucht, einen Skalar als Feld zu verwenden" #: debug.c:1856 #, c-format msgid "Watchpoint %d deleted because parameter is out of scope.\n" -msgstr "" +msgstr "Watchpoint %d wurde gelöscht, weil der Parameter außerhalb des Gültigkeitsbereichs ist.\n" #: debug.c:1867 #, c-format msgid "Display %d deleted because parameter is out of scope.\n" -msgstr "" +msgstr "Anzuzeigendes Element %d wurde gelöscht, weil der Parameter außerhalb des Gültigkeitsbereichs ist.\n" #: debug.c:1900 #, c-format msgid " in file `%s', line %d\n" -msgstr "" +msgstr " in Datei »%s«, Zeile %d\n" #: debug.c:1921 #, c-format msgid " at `%s':%d" -msgstr "" +msgstr " bei »%s«:%d" #: debug.c:1937 debug.c:2000 #, c-format msgid "#%ld\tin " -msgstr "" +msgstr "#%ld\tin " #: debug.c:1974 #, c-format msgid "More stack frames follow ...\n" -msgstr "" +msgstr "Weitere Stapelrahmen folgen ...\n" #: debug.c:2017 -#, fuzzy msgid "invalid frame number" -msgstr "Ungültiges Bereichsende" +msgstr "Ungültige Rahmennummer" #: debug.c:2200 #, c-format msgid "Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d" -msgstr "" +msgstr "Hinweis: Breakpont %d (aktiv, ignoriert für die nächsten %ld Treffer) wird auch an %s:%d gesetzt" #: debug.c:2207 #, c-format msgid "Note: breakpoint %d (enabled), also set at %s:%d" -msgstr "" +msgstr "Hinweis: Breakpont %d (aktiv) wird auch an %s:%d gesetzt" #: debug.c:2214 #, c-format msgid "Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d" -msgstr "" +msgstr "Hinweis: Breakpont %d (inaktiv, ignoriert für die nächsten %ld Treffer) wird auch von %s:%d gesetzt" #: debug.c:2221 #, c-format msgid "Note: breakpoint %d (disabled), also set at %s:%d" -msgstr "" +msgstr "Hinweis: Breakpont %d (inaktiv) wird auch an %s:%d gesetzt" #: debug.c:2238 #, c-format msgid "Breakpoint %d set at file `%s', line %d\n" -msgstr "" +msgstr "Breakpont %d wird auf Datei %s, Zeile %d gesetzt\n" #: debug.c:2340 #, c-format msgid "Can't set breakpoint in file `%s'\n" -msgstr "" +msgstr "In Datei »%s« kann kein Breakpoint gesetzt werden\n" #: debug.c:2369 debug.c:2492 debug.c:3350 -#, fuzzy, c-format +#, c-format msgid "line number %d in file `%s' out of range" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "Zeile Nummer %d in Datei »%s« liegt außerhalb des gültigen Bereichs" #: debug.c:2373 #, c-format msgid "Can't find rule!!!\n" -msgstr "" +msgstr "Die Regel kann nicht gefunden werden!!!\n" #: debug.c:2375 #, c-format msgid "Can't set breakpoint at `%s':%d\n" -msgstr "" +msgstr "In »%s«:%d kann kein Breakpoint gesetzt werden\n" #: debug.c:2387 #, c-format msgid "Can't set breakpoint in function `%s'\n" -msgstr "" +msgstr "In Funktion »%s« kann kein Breakpoint gesetzt werden\n" #: debug.c:2403 #, c-format msgid "breakpoint %d set at file `%s', line %d is unconditional\n" -msgstr "" +msgstr "Breakpoint %d gestzt auf Datei »%s« Zeile %d ist bedingungslos\n" #: debug.c:2508 debug.c:2530 #, c-format msgid "Deleted breakpoint %d" -msgstr "" +msgstr "Breakpoint %d wurde gelöscht" #: debug.c:2514 #, c-format msgid "No breakpoint(s) at entry to function `%s'\n" -msgstr "" +msgstr "Am Beginn von Funktion »%s« gibt es keine Breakpoints\n" #: debug.c:2541 -#, fuzzy, c-format +#, c-format msgid "No breakpoint at file `%s', line #%d\n" -msgstr "Fehler beim Lesen der Eingabedatei »%s«: %s" +msgstr "Bei Datei »%s« Zeile %d gibt es keine Breakpoints\n" #: debug.c:2596 debug.c:2637 debug.c:2657 debug.c:2700 msgid "invalid breakpoint number" -msgstr "" +msgstr "Ungtige Breakpoint/Nummer" #: debug.c:2612 msgid "Delete all breakpoints? (y or n) " -msgstr "" +msgstr "Alle Breakpoints löschen? (j oder n) " #: debug.c:2613 debug.c:2923 debug.c:2976 msgid "y" -msgstr "" +msgstr "j" #: debug.c:2662 #, c-format msgid "Will ignore next %ld crossing(s) of breakpoint %d.\n" -msgstr "" +msgstr "die nächsten %ld Überschreitungen von Breakpoint %d werden ignoriert.\n" #: debug.c:2666 #, c-format msgid "Will stop next time breakpoint %d is reached.\n" -msgstr "" +msgstr "wenn Breakpoint %d das nächste mal erreicht wird, wird angehalten\n" #: debug.c:2783 #, c-format msgid "Can only debug programs provided with the `-f' option.\n" -msgstr "" +msgstr "Es können nur Programme untersucht werden, die mittels der Option »-f« übergeben wurden.\n" #: debug.c:2908 #, c-format msgid "Failed to restart debugger" -msgstr "" +msgstr "Der Debugger konnte nicht neu gestartet werden" #: debug.c:2922 msgid "Program already running. Restart from beginning (y/n)? " -msgstr "" +msgstr "das Programm läfut bereits. Neu starten (j/n}? " #: debug.c:2926 #, c-format msgid "Program not restarted\n" -msgstr "" +msgstr "Das Programm wurde nicht neu gestartet\n" #: debug.c:2936 #, c-format msgid "error: cannot restart, operation not allowed\n" -msgstr "" +msgstr "Fehler: Neustart nicht möglich da die Operation verboten ist\n" #: debug.c:2942 #, c-format msgid "error (%s): cannot restart, ignoring rest of the commands\n" -msgstr "" +msgstr "Fehler (%s): Neustart nicht möglich, der Rest der Befehle wird ignoriert\n" #: debug.c:2950 #, c-format msgid "Starting program: \n" -msgstr "" +msgstr "Das Programm wird gestartet: \n" #: debug.c:2959 #, c-format msgid "Program exited %s with exit value: %d\n" -msgstr "" +msgstr "Das Programm verließ %s mit einem Rückgabewert: %d\n" #: debug.c:2975 msgid "The program is running. Exit anyway (y/n)? " -msgstr "" +msgstr "Das Prgramm läuft. Trotzdem beenden (j/n) " #: debug.c:3010 #, c-format msgid "Not stopped at any breakpoint; argument ignored.\n" -msgstr "" +msgstr "Es wird an keinem Breakpoint gestoppt; das Argument wird ignoriert.\n" #: debug.c:3015 #, c-format msgid "invalid breakpoint number %d." -msgstr "" +msgstr "ungültige Breakpointnummer %d." #: debug.c:3020 #, c-format msgid "Will ignore next %ld crossings of breakpoint %d.\n" -msgstr "" +msgstr "Die nächsten %ld Überschreitungen von Breakpoint %d werden ignoriert.\n" #: debug.c:3207 #, c-format msgid "'finish' not meaningful in the outermost frame main()\n" -msgstr "" +msgstr "»finish« hat in main() des äußersten Rahmens keine Bedeutung\n" #: debug.c:3212 #, c-format msgid "Run till return from " -msgstr "" +msgstr "Laufen bis zur Rückkehr von " #: debug.c:3255 #, c-format msgid "'return' not meaningful in the outermost frame main()\n" -msgstr "" +msgstr "»return« hat in main() des äußersten Rahmens keine Bedeutung\n" #: debug.c:3369 #, c-format msgid "Can't find specified location in function `%s'\n" -msgstr "" +msgstr "Die angegebene Position in Funktion »%s« kann nicht gefunden werden\n" #: debug.c:3377 -#, fuzzy, c-format +#, c-format msgid "invalid source line %d in file `%s'" -msgstr "Quelldatei »%s« wurde bereits eingebunden" +msgstr "ungültige Quellzeilennummer %d in Datei »%s«" #: debug.c:3392 #, c-format msgid "Can't find specified location %d in file `%s'\n" -msgstr "" +msgstr "Der Zielpunkt %d in Datei »%s« ist nicht auffindbar\n" #: debug.c:3424 -#, fuzzy, c-format +#, c-format msgid "element not in array\n" -msgstr "delete: Index »%s« ist in Feld »%s« nicht vorhanden" +msgstr "Das Element ist kein Feld\n" #: debug.c:3424 #, c-format msgid "untyped variable\n" -msgstr "" +msgstr "untypisierte Variable\n" #: debug.c:3466 #, c-format msgid "Stopping in %s ...\n" -msgstr "" +msgstr "Stopp in %s ...\n" #: debug.c:3543 #, c-format msgid "'finish' not meaningful with non-local jump '%s'\n" -msgstr "" +msgstr "»finish« hat bei dem nichtlokalen Sprung »%s« keine Bedeutung\n" #: debug.c:3550 #, c-format msgid "'until' not meaningful with non-local jump '%s'\n" -msgstr "" +msgstr "»finish« hat bei dem nichtlokalen Sprung »%s« keine Bedeutung\n" #: debug.c:4185 msgid "\t------[Enter] to continue or q [Enter] to quit------" -msgstr "" +msgstr "\t-[Eingabe] um fort zu fahren oder b [Eingabe] für geenden -" #: debug.c:4186 msgid "q" -msgstr "" +msgstr "b" #: debug.c:5001 -#, fuzzy, c-format +#, c-format msgid "[\"%s\"] not in array `%s'" -msgstr "delete: Index »%s« ist in Feld »%s« nicht vorhanden" +msgstr "[\"%s\"] ist in Feld »%s« nicht vorhanden" #: debug.c:5207 #, c-format msgid "sending output to stdout\n" -msgstr "" +msgstr "Ausgabe wird an die Standardausgabe geschickt\n" #: debug.c:5247 msgid "invalid number" -msgstr "" +msgstr "ungültige Zahl" #: debug.c:5381 -#, fuzzy, c-format +#, c-format msgid "`%s' not allowed in current context; statement ignored" -msgstr "»exit« kann im aktuellen Kontext nicht aufgerufen werden" +msgstr "»%s« ist im aktuellen Kontext nicht zulässig; der Ausdruck wird ignoriert" #: debug.c:5389 -#, fuzzy msgid "`return' not allowed in current context; statement ignored" -msgstr "»exit« kann im aktuellen Kontext nicht aufgerufen werden" +msgstr "»reeturn« ist im aktuellen Kontext nicht zulässig; der Ausdruck wird ignoriert" #: debug.c:5590 #, c-format msgid "No symbol `%s' in current context" -msgstr "" +msgstr "Im aktuelln Kontext gibt es kein Symbol »%s«" -#: dfa.c:1118 dfa.c:1121 dfa.c:1142 dfa.c:1150 dfa.c:1162 dfa.c:1197 -#: dfa.c:1206 dfa.c:1209 dfa.c:1214 dfa.c:1228 dfa.c:1275 +#: dfa.c:998 dfa.c:1001 dfa.c:1021 dfa.c:1031 dfa.c:1043 dfa.c:1094 dfa.c:1103 +#: dfa.c:1106 dfa.c:1111 dfa.c:1124 dfa.c:1191 msgid "unbalanced [" -msgstr "" +msgstr "nicht geschlossene [" -#: dfa.c:1174 -#, fuzzy +#: dfa.c:1052 msgid "invalid character class" -msgstr "Ungültiger Name für eine Zeichenklasse" +msgstr "ungültige Zeichenklasse" -#: dfa.c:1316 +#: dfa.c:1228 msgid "character class syntax is [[:space:]], not [:space:]" -msgstr "" +msgstr "Die Syntax für Zeichenklassen ist [[:space:]], nicht [:space:]" -#: dfa.c:1366 +#: dfa.c:1280 msgid "unfinished \\ escape" -msgstr "" +msgstr "nicht beendetes \\ Escape" -#: dfa.c:1513 regcomp.c:161 +#: dfa.c:1427 regcomp.c:161 msgid "Invalid content of \\{\\}" msgstr "Ungültiger Inhalt von \\{\\}" -#: dfa.c:1516 regcomp.c:176 +#: dfa.c:1430 regcomp.c:176 msgid "Regular expression too big" msgstr "Regulärer Ausdruck ist zu groß" -#: dfa.c:1936 +#: dfa.c:1847 msgid "unbalanced (" -msgstr "" +msgstr "nicht geschlossene (" -#: dfa.c:2062 +#: dfa.c:1973 msgid "no syntax specified" -msgstr "" +msgstr "keine Syntax angegeben" -#: dfa.c:2070 +#: dfa.c:1981 msgid "unbalanced )" -msgstr "" +msgstr "nicht geöffnete )" #: eval.c:394 #, c-format @@ -1947,38 +1883,32 @@ msgid "extensions are not allowed in sandbox mode" msgstr "Erweiterungen sind im Sandbox-Modus nicht erlaubt" #: ext.c:92 -#, fuzzy msgid "-l / @load are gawk extensions" -msgstr "»@include« ist eine gawk-Erweiterung" +msgstr "-l / @load sind gawk-Erweiterungen" #: ext.c:95 msgid "load_ext: received NULL lib_name" -msgstr "" +msgstr "load_ext: NULL lib_name erhalten" #: ext.c:98 -#, fuzzy, c-format +#, c-format msgid "load_ext: cannot open library `%s' (%s)\n" -msgstr "Fatal: extension: »%s« kann nicht geöffnet werden (%s)\n" +msgstr "load_ext: Bibliothek »%s« kann nicht geöffnet werden (%s)\n" #: ext.c:104 -#, fuzzy, c-format -msgid "" -"load_ext: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n" -msgstr "" -"Fatal: Erweiterung: Bibliothek »%s«: definiert »plugin_is_GPL_compatible« " -"nicht (%s)\n" +#, c-format +msgid "load_ext: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n" +msgstr "load_ext: Bibliothek »%s«: definiert »plugin_is_GPL_compatible« nicht (%s)\n" #: ext.c:110 -#, fuzzy, c-format +#, c-format msgid "load_ext: library `%s': cannot call function `%s' (%s)\n" -msgstr "" -"Fatal: Erweiterung: Bibliothek »%s«: Funktion »%s« kann nicht aufgerufen " -"werden (%s)\n" +msgstr "load_ext: Bibliothek »%s«: Funktion »%s« kann nicht aufgerufen werden (%s)\n" #: ext.c:114 #, c-format msgid "load_ext: library `%s' initialization routine `%s' failed\n" -msgstr "" +msgstr "load_ext: die Initialisierungsroutine %2$s von Bibliothek »%1$s« ist gescheitert\n" #: ext.c:174 msgid "`extension' is a gawk extension" @@ -1986,54 +1916,46 @@ msgstr "»extension« ist eine gawk-Erweiterung" #: ext.c:177 msgid "extension: received NULL lib_name" -msgstr "" +msgstr "extension: NULL lib_name erhalten" #: ext.c:180 -#, fuzzy, c-format +#, c-format msgid "extension: cannot open library `%s' (%s)" -msgstr "Fatal: extension: »%s« kann nicht geöffnet werden (%s)\n" +msgstr "extension: Bibliothek »%s« kann nicht geöffnet werden (%s)" #: ext.c:186 -#, fuzzy, c-format -msgid "" -"extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)" -msgstr "" -"Fatal: Erweiterung: Bibliothek »%s«: definiert »plugin_is_GPL_compatible« " -"nicht (%s)\n" +#, c-format +msgid "extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)" +msgstr "extension: Bibliothek »%s«: definiert »plugin_is_GPL_compatible« nicht (%s)" #: ext.c:190 -#, fuzzy, c-format +#, c-format msgid "extension: library `%s': cannot call function `%s' (%s)" -msgstr "" -"Fatal: Erweiterung: Bibliothek »%s«: Funktion »%s« kann nicht aufgerufen " -"werden (%s)\n" +msgstr "extension: Bibliothek »%s«: Funktion »%s« kann nicht aufgerufen werden (%s)" #: ext.c:221 -#, fuzzy msgid "make_builtin: missing function name" -msgstr "Erweiterung: Funktionsname fehlt" +msgstr "make_builtin: Funktionsname fehlt" #: ext.c:236 -#, fuzzy, c-format +#, c-format msgid "make_builtin: can't redefine function `%s'" -msgstr "Erweiterung: Funktion »%s« kann nicht neu definiert werden" +msgstr "make_builtin: Funktion »%s« kann nicht neu definiert werden" #: ext.c:240 -#, fuzzy, c-format +#, c-format msgid "make_builtin: function `%s' already defined" -msgstr "Erweiterung: Funktion »%s« wurde bereits definiert" +msgstr "make_builtin: Funktion »%s« wurde bereits definiert" #: ext.c:244 -#, fuzzy, c-format +#, c-format msgid "make_builtin: function name `%s' previously defined" -msgstr "Erweiterung: Funktion »%s« wurde bereits vorher definiert" +msgstr "make_builtin: Funktion »%s« wurde bereits vorher definiert" #: ext.c:246 -#, fuzzy, c-format +#, c-format msgid "make_builtin: can't use gawk built-in `%s' as function name" -msgstr "" -"Erweiterung: die eingebaute Funktion »%s« kann nicht als Funktionsname " -"verwendet werden" +msgstr "make_builtin: die in gawk eingebaute Funktion »%s« kann nicht als Funktionsname verwendet werden" #: ext.c:249 ext.c:304 #, c-format @@ -2041,43 +1963,38 @@ msgid "make_builtin: negative argument count for function `%s'" msgstr "make_builtin: negative Anzahl von Argumenten für Funktion »%s«" #: ext.c:276 -#, fuzzy msgid "extension: missing function name" msgstr "Erweiterung: Funktionsname fehlt" #: ext.c:279 ext.c:283 -#, fuzzy, c-format +#, c-format msgid "extension: illegal character `%c' in function name `%s'" -msgstr "Erweiterung: unzulässiges Zeichen »%c« in Funktionsname »%s«" +msgstr "extension: unzulässiges Zeichen »%c« in Funktionsname »%s«" #: ext.c:291 -#, fuzzy, c-format +#, c-format msgid "extension: can't redefine function `%s'" -msgstr "Erweiterung: Funktion »%s« kann nicht neu definiert werden" +msgstr "extension: Funktion »%s« kann nicht neu definiert werden" #: ext.c:295 -#, fuzzy, c-format +#, c-format msgid "extension: function `%s' already defined" -msgstr "Erweiterung: Funktion »%s« wurde bereits definiert" +msgstr "extension: Funktion »%s« wurde bereits definiert" #: ext.c:299 -#, fuzzy, c-format +#, c-format msgid "extension: function name `%s' previously defined" -msgstr "Funktion »%s« wurde bereits definiert" +msgstr "extension: Funktion »%s« wurde bereits vorher definiert" #: ext.c:301 -#, fuzzy, c-format +#, c-format msgid "extension: can't use gawk built-in `%s' as function name" -msgstr "" -"Erweiterung: die eingebaute Funktion »%s« kann nicht als Funktionsname " -"verwendet werden" +msgstr "extension: die eingebaute Funktion »%s« kann nicht als Funktionsname verwendet werden" #: ext.c:375 #, c-format msgid "function `%s' defined to take no more than %d argument(s)" -msgstr "" -"Funktion »%s« wird als Funktion definiert, die nie mehr als %d Argument(e) " -"akzeptiert" +msgstr "Funktion »%s« wird als Funktion definiert, die nie mehr als %d Argument(e) akzeptiert" #: ext.c:378 #, c-format @@ -2087,384 +2004,347 @@ msgstr "Funktion »%s«: fehlendes Argument #%d" #: ext.c:395 #, c-format msgid "function `%s': argument #%d: attempt to use scalar as an array" -msgstr "" -"Funktion »%s«: Argument #%d: Es wird versucht, einen Skalar als Feld zu " -"verwenden" +msgstr "Funktion »%s«: Argument #%d: Es wird versucht, einen Skalar als Feld zu verwenden" #: ext.c:399 #, c-format msgid "function `%s': argument #%d: attempt to use array as a scalar" -msgstr "" -"Funktion »%s«: Argument #%d: Es wird versucht, ein Feld als Skalar zu " -"verwenden" +msgstr "Funktion »%s«: Argument #%d: Es wird versucht, ein Feld als Skalar zu verwenden" #: ext.c:413 msgid "dynamic loading of library not supported" -msgstr "" +msgstr "das dynamische Laden von Bibliotheken wird nicht unterstützt" #: extension/filefuncs.c:159 -#, fuzzy msgid "chdir: called with incorrect number of arguments, expecting 1" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "chdir: Aufgruf mit einer ungültigen Anzahl von Argumenten, 1 wird erwartet" #: extension/filefuncs.c:439 #, c-format msgid "stat: unable to read symbolic link `%s'" -msgstr "" +msgstr "stst: die symbolische Verknüpfung »%s« kann nicht gelesenb werden" #: extension/filefuncs.c:472 -#, fuzzy msgid "stat: called with wrong number of arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "stat: Aufruf mit falscher Anzahl Argumenten" #: extension/filefuncs.c:479 -#, fuzzy msgid "stat: bad parameters" -msgstr "%s: ist ein Parameter\n" +msgstr "stat: ungültige Parameter" #: extension/filefuncs.c:533 -#, fuzzy, c-format +#, c-format msgid "fts init: could not create variable %s" -msgstr "index: Zweites Argument ist kein string" +msgstr "fts_init: Variable %s konnte nicht angelegt werden" #: extension/filefuncs.c:554 -#, fuzzy msgid "fts is not supported on this system" -msgstr "»%s« wird im alten awk nicht unterstützt" +msgstr "fts wird auf diesem System nicht unterstützt" #: extension/filefuncs.c:573 msgid "fill_stat_element: could not create array" -msgstr "" +msgstr "fill_stat_element: das Feld konnte nicht angelegt werden" #: extension/filefuncs.c:582 msgid "fill_stat_element: could not set element" -msgstr "" +msgstr "fill_stat_element: das Element konnte nicht gesetzt werden" #: extension/filefuncs.c:597 -#, fuzzy msgid "fill_path_element: could not set element" -msgstr "index: Zweites Argument ist kein string" +msgstr "fill_path_element: das Element konnte nicht gesetzt werden" #: extension/filefuncs.c:613 msgid "fill_error_element: could not set element" -msgstr "" +msgstr "fill_error_element: das Element konnte nicht gesetzt werden" #: extension/filefuncs.c:660 extension/filefuncs.c:707 msgid "fts-process: could not create array" -msgstr "" +msgstr "fts-process: das Feld konnte nicht anglegt werden" #: extension/filefuncs.c:670 extension/filefuncs.c:717 #: extension/filefuncs.c:735 -#, fuzzy msgid "fts-process: could not set element" -msgstr "index: Zweites Argument ist kein string" +msgstr "fts-process: das Element konnte nicht gesetzt werden" #: extension/filefuncs.c:784 -#, fuzzy msgid "fts: called with incorrect number of arguments, expecting 3" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "fts: Aufruf mit falscher Anzahl an Argumenten, es werden 3 erwartet" #: extension/filefuncs.c:787 -#, fuzzy msgid "fts: bad first parameter" -msgstr "%s: ist ein Parameter\n" +msgstr "fts: ungültiger Parameter" #: extension/filefuncs.c:793 -#, fuzzy msgid "fts: bad second parameter" -msgstr "%s: ist ein Parameter\n" +msgstr "fts: ungültiger zweiter Parameter" #: extension/filefuncs.c:799 -#, fuzzy msgid "fts: bad third parameter" -msgstr "%s: ist ein Parameter\n" +msgstr "%s: ist ein Parameter" #: extension/filefuncs.c:806 -#, fuzzy msgid "fts: could not flatten array\n" -msgstr "»%s« ist kein gültiger Variablenname" +msgstr "fts: ungültiger dritter Parameter\n" #: extension/filefuncs.c:824 msgid "fts: ignoring sneaky FTS_NOSTAT flag. nyah, nyah, nyah." -msgstr "" +msgstr "fts: die heimtückische Kennung FTS_NOSTAT wird ignoriert, ätsch bätsch." #: extension/filefuncs.c:841 msgid "fts: clear_array() failed\n" -msgstr "" +msgstr "fts: clear_array() ist gescheitert\n" #: extension/fnmatch.c:112 -#, fuzzy msgid "fnmatch: called with less than three arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "fnmatch: Aufruf mit weniger als drei Argumenten" #: extension/fnmatch.c:115 -#, fuzzy msgid "fnmatch: called with more than three arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "fnmatch: Aufruf mit mehr als drei Argumenten" #: extension/fnmatch.c:118 -#, fuzzy msgid "fnmatch: could not get first argument" -msgstr "strftime: Das erste Argument ist kein String" +msgstr "fnmatch: Das erste Argument konnte nicht gelesen werden" #: extension/fnmatch.c:123 -#, fuzzy msgid "fnmatch: could not get second argument" -msgstr "index: Zweites Argument ist kein string" +msgstr "fnmatch: Das zweite Argument konnte nicht gelesen werden" #: extension/fnmatch.c:128 msgid "fnmatch: could not get third argument" -msgstr "" +msgstr "fnmatch: Das dritte Argument konnte nicht gelesen werden" #: extension/fnmatch.c:141 msgid "fnmatch is not implemented on this system\n" -msgstr "" +msgstr "fnmatch ist auf diesem System nicht implementiert\n" #: extension/fnmatch.c:173 msgid "fnmatch init: could not add FNM_NOMATCH variable" -msgstr "" +msgstr "fnmatch_init: eine FNM_NOMATCH-Variable konnte nicht hinzu gefügt werden" #: extension/fnmatch.c:183 #, c-format msgid "fnmatch init: could not set array element %s" -msgstr "" +msgstr "fnmatch_init: das Feldelement %s konnte nicht initialisiert werden" #: extension/fnmatch.c:193 msgid "fnmatch init: could not install FNM array" -msgstr "" +msgstr "fnmatch_init: das FNM-Feld konnte nicht gesetzt werden." #: extension/fork.c:81 -#, fuzzy msgid "fork: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "fork: Aufruf mit zu vielen Argumenten" #: extension/fork.c:94 msgid "fork: PROCINFO is not an array!" -msgstr "" +msgstr "fork: PROCINFO ist kein Feld!" #: extension/fork.c:118 -#, fuzzy msgid "waitpid: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "waitpid: Aufruf mit zu vielen Argumenten" #: extension/fork.c:126 -#, fuzzy msgid "wait: called with no arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "wait: Aufruf ohne Argumente" #: extension/fork.c:143 -#, fuzzy msgid "wait: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "wait: Aufruf mit zu vielen Argumenten" #: extension/inplace.c:130 msgid "inplace_begin: in-place editing already active" -msgstr "" +msgstr "inplace_begin: direktes Editieren ist bereits aktiv" #: extension/inplace.c:133 extension/inplace.c:207 #, c-format msgid "inplace_begin: expects 2 arguments but called with %d" -msgstr "" +msgstr "inplace_begin: erwartet 2 Argumente aber wurde aufgerufen mit %d" #: extension/inplace.c:136 msgid "inplace_begin: cannot retrieve 1st argument as a string filename" -msgstr "" +msgstr "inplace_begin: das erste Argument ist kein Dateiname" #: extension/inplace.c:144 #, c-format msgid "inplace_begin: disabling in-place editing for invalid FILENAME `%s'" -msgstr "" +msgstr "inplace_begin: direktes Editieren wird deaktiviert wegen des ungültigen Dateinamens »%s«" #: extension/inplace.c:151 -#, fuzzy, c-format +#, c-format msgid "inplace_begin: Cannot stat `%s' (%s)" -msgstr "Fatal: extension: »%s« kann nicht geöffnet werden (%s)\n" +msgstr "inplace_begin: Status von »%s« kann nicht ermittelt werden (%s)" #: extension/inplace.c:158 -#, fuzzy, c-format +#, c-format msgid "inplace_begin: `%s' is not a regular file" -msgstr "»%s« ist kein gültiger Variablenname" +msgstr "inplace_begin: »%s« ist keine reguläre Datei" #: extension/inplace.c:169 #, c-format msgid "inplace_begin: mkstemp(`%s') failed (%s)" -msgstr "" +msgstr "inplace_begin: mkstemp(»%s«) ist gescheitert (%s)" #: extension/inplace.c:178 -#, fuzzy, c-format +#, c-format msgid "inplace_begin: chmod failed (%s)" -msgstr "%s: close ist gescheitert (%s)" +msgstr "inplace_begin:: chmod ist gescheitert (%s)" #: extension/inplace.c:185 #, c-format msgid "inplace_begin: dup(stdout) failed (%s)" -msgstr "" +msgstr "inplace_begin: dup(stdout) ist gescheitert (%s)" #: extension/inplace.c:188 #, c-format msgid "inplace_begin: dup2(%d, stdout) failed (%s)" -msgstr "" +msgstr "inplace_begin: dup2(%d, stdout) ist gescheitert (%s)" #: extension/inplace.c:191 -#, fuzzy, c-format +#, c-format msgid "inplace_begin: close(%d) failed (%s)" -msgstr "%s: close ist gescheitert (%s)" +msgstr "inplace_begin: close(%d) ist gescheitert (%s)" #: extension/inplace.c:210 msgid "inplace_end: cannot retrieve 1st argument as a string filename" -msgstr "" +msgstr "inplace_end: das erste Argument ist kein Dateiname" #: extension/inplace.c:217 msgid "inplace_end: in-place editing not active" -msgstr "" +msgstr "inplace_end: direktes Editieren ist nicht aktiv" #: extension/inplace.c:223 #, c-format msgid "inplace_end: dup2(%d, stdout) failed (%s)" -msgstr "" +msgstr "inplace_end: dup2(%d, stdout) ist gescheitert (%s)" #: extension/inplace.c:226 -#, fuzzy, c-format +#, c-format msgid "inplace_end: close(%d) failed (%s)" -msgstr "%s: close ist gescheitert (%s)" +msgstr "inplace_end: close(%d) ist gescheitert (%s)" #: extension/inplace.c:230 #, c-format msgid "inplace_end: fsetpos(stdout) failed (%s)" -msgstr "" +msgstr "inplace_end: fsetpos(stdout) ist gescheitert (%s)" #: extension/inplace.c:243 -#, fuzzy, c-format +#, c-format msgid "inplace_end: link(`%s', `%s') failed (%s)" -msgstr "Das Leeren der Pipe »%s« ist gescheitert (%s)" +msgstr "inplace_end: link(»%s«, »%s«) ist gescheitert (%s)" #: extension/inplace.c:253 -#, fuzzy, c-format +#, c-format msgid "inplace_end: rename(`%s', `%s') failed (%s)" -msgstr "Das Schließen des Dateideskriptors %d (»%s«) ist gescheitert (%s)" +msgstr "inplace_end: rename(»%s«, »%s«) ist gescheitert (%s)" #: extension/ordchr.c:69 -#, fuzzy msgid "ord: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "ord: Aufruf mit yu vielen Argumenten" #: extension/ordchr.c:75 -#, fuzzy msgid "ord: called with no arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "ord: Aufruf ohne Argumente" #: extension/ordchr.c:77 -#, fuzzy msgid "ord: called with inappropriate argument(s)" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "ord: Aufruf mit ungeeigneten Argumenten" #: extension/ordchr.c:99 -#, fuzzy msgid "chr: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "chr: Aufruf mit zu vielen Argumenten" #: extension/ordchr.c:109 -#, fuzzy msgid "chr: called with no arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "chr: Aufruf ohne Argumente" #: extension/ordchr.c:111 -#, fuzzy msgid "chr: called with inappropriate argument(s)" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "chr: Aufruf mit ungeeigneten Argumenten" -#: extension/readdir.c:281 +#: extension/readdir.c:277 #, c-format msgid "dir_take_control_of: opendir/fdopendir failed: %s" -msgstr "" +msgstr "dir_take_control_of: opendir/fdopendir ist gescheitert: %s" -#: extension/readfile.c:113 -#, fuzzy +#: extension/readfile.c:84 msgid "readfile: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "readfile: Aufruf mit zu vielen Argumenten" -#: extension/readfile.c:137 -#, fuzzy +#: extension/readfile.c:118 msgid "readfile: called with no arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "readfile: Aufruf ohen Argumente" #: extension/rwarray.c:124 -#, fuzzy msgid "writea: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "writea: Aufruf mit zu vielen Argumenten" #: extension/rwarray.c:131 -#, fuzzy, c-format +#, c-format msgid "do_writea: argument 0 is not a string\n" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "do_writea: das Argument 0 ist keine Zeichenkette\n" #: extension/rwarray.c:137 -#, fuzzy, c-format +#, c-format msgid "do_writea: argument 1 is not an array\n" -msgstr "split: das vierte Argument ist kein Feld" +msgstr "do_writea: das Argument 1 ist kein Feld\n" #: extension/rwarray.c:184 #, c-format msgid "write_array: could not flatten array\n" -msgstr "" +msgstr "write_array: das Feld konnte nicht niveliert werden\n" #: extension/rwarray.c:198 #, c-format msgid "write_array: could not release flattened array\n" -msgstr "" +msgstr "write_array: das nivelierte Feld konnte nicht frei gegeben werden\n" #: extension/rwarray.c:280 -#, fuzzy msgid "reada: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "reada: Aufruf mit zu vielen Argumenten" #: extension/rwarray.c:287 -#, fuzzy, c-format +#, c-format msgid "do_reada: argument 0 is not a string\n" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "do_reada: Argument 0 ist keine Zeichenkette\n" #: extension/rwarray.c:293 -#, fuzzy, c-format +#, c-format msgid "do_reada: argument 1 is not an array\n" -msgstr "match: das dritte Argument ist kein Array" +msgstr "do_reada: Argument 1 ist kein Feld\n" #: extension/rwarray.c:337 #, c-format msgid "do_reada: clear_array failed\n" -msgstr "" +msgstr "do_reada: clear_array ist gescheitert\n" #: extension/rwarray.c:374 #, c-format msgid "read_array: set_array_element failed\n" -msgstr "" +msgstr "read_array: set_array_element ist gescheitert\n" -#: extension/time.c:113 -#, fuzzy +#: extension/time.c:106 msgid "gettimeofday: ignoring arguments" -msgstr "mktime: Das Argument ist kein String" +msgstr "gettimeofday: die Argumente werden ignoriert" -#: extension/time.c:144 +#: extension/time.c:137 msgid "gettimeofday: not supported on this platform" -msgstr "" +msgstr "gettimeofday: wird auf dieser Plattform nicht unterstützt" -#: extension/time.c:165 -#, fuzzy +#: extension/time.c:158 msgid "sleep: called with too many arguments" -msgstr "sqrt: das Argument %g ist negativ" +msgstr "sleep: Aufruf mit zu vielen Argumenten" -#: extension/time.c:168 -#, fuzzy +#: extension/time.c:161 msgid "sleep: missing required numeric argument" -msgstr "exp: das Argument ist keine Zahl" +msgstr "sleep: das erforderliche numerische Argument fehlt" -#: extension/time.c:174 -#, fuzzy +#: extension/time.c:167 msgid "sleep: argument is negative" -msgstr "exp: das Argument %g liegt außerhalb des gültigen Bereichs" +msgstr "sleep: das Argument ist negativ" -#: extension/time.c:208 +#: extension/time.c:201 msgid "sleep: not supported on this platform" -msgstr "" +msgstr "sleep: wird auf dieser Plattform nicht unterstützt" #: field.c:345 msgid "NF set to negative value" @@ -2484,21 +2364,15 @@ msgstr "split: das zweite Argument ist kein Feld" #: field.c:993 msgid "split: cannot use the same array for second and fourth args" -msgstr "" -"split: als zweites und viertes Argument kann nicht das gleiche Feld " -"verwendet werden" +msgstr "split: als zweites und viertes Argument kann nicht das gleiche Feld verwendet werden" #: field.c:998 msgid "split: cannot use a subarray of second arg for fourth arg" -msgstr "" -"split: Ein untergeordnetes Feld des zweiten Arguments kann nicht als viertes " -"Argument verwendet werden" +msgstr "split: Ein untergeordnetes Feld des zweiten Arguments kann nicht als viertes Argument verwendet werden" #: field.c:1001 msgid "split: cannot use a subarray of fourth arg for second arg" -msgstr "" -"split: Ein untergeordnetes Feld des vierten Arguments kann nicht als zweites " -"Argument verwendet werden" +msgstr "split: Ein untergeordnetes Feld des vierten Arguments kann nicht als zweites Argument verwendet werden" #: field.c:1032 msgid "split: null string for third arg is a gawk extension" @@ -2518,21 +2392,15 @@ msgstr "patsplit: Das dritte Argument darf nicht Null sein" #: field.c:1087 msgid "patsplit: cannot use the same array for second and fourth args" -msgstr "" -"patsplit: als zweites und viertes Argument kann nicht das gleiche Feld " -"verwendet werden" +msgstr "patsplit: als zweites und viertes Argument kann nicht das gleiche Feld verwendet werden" #: field.c:1092 msgid "patsplit: cannot use a subarray of second arg for fourth arg" -msgstr "" -"patsplit: Ein untergeordnetes Feld des zweiten Arguments kann nicht als " -"viertes Argument verwendet werden" +msgstr "patsplit: Ein untergeordnetes Feld des zweiten Arguments kann nicht als viertes Argument verwendet werden" #: field.c:1095 msgid "patsplit: cannot use a subarray of fourth arg for second arg" -msgstr "" -"patsplit: Ein untergeordnetes Feld des vierten Arguments kann nicht als " -"zweites Argument verwendet werden" +msgstr "patsplit: Ein untergeordnetes Feld des vierten Arguments kann nicht als zweites Argument verwendet werden" #: field.c:1133 msgid "`FIELDWIDTHS' is a gawk extension" @@ -2557,39 +2425,38 @@ msgstr "»FPAT« ist eine gawk-Erweiterung" #: gawkapi.c:146 msgid "awk_value_to_node: received null retval" -msgstr "" +msgstr "awk_value_to_node: Rückgabewert Null erhalten" #: gawkapi.c:384 msgid "node_to_awk_value: received null node" -msgstr "" +msgstr "node_to_awk_value: Null-Knoten erhalten" #: gawkapi.c:387 msgid "node_to_awk_value: received null val" -msgstr "" +msgstr "node_to_awk_value: Null-Wert erhalten" -#: gawkapi.c:807 -#, fuzzy +#: gawkapi.c:808 msgid "remove_element: received null array" -msgstr "length: Argument ist ein Feld" +msgstr "remove_element: Null-Feld erhalten" -#: gawkapi.c:810 +#: gawkapi.c:811 msgid "remove_element: received null subscript" -msgstr "" +msgstr "remove_element: Null-Index erhalten" -#: gawkapi.c:947 +#: gawkapi.c:948 #, c-format msgid "api_flatten_array: could not convert index %d\n" -msgstr "" +msgstr "api_flatten_array: Index %d konnte nicht umgewandelt werden\n" -#: gawkapi.c:952 +#: gawkapi.c:953 #, c-format msgid "api_flatten_array: could not convert value %d\n" -msgstr "" +msgstr "api_flatten_array: Wert %d konnte nicht umgewandelt werden\n" #: getopt.c:604 getopt.c:633 -#, fuzzy, c-format +#, c-format msgid "%s: option '%s' is ambiguous; possibilities:" -msgstr "%s: Option »%s« ist mehrdeutig\n" +msgstr "%s: Option »%s« ist mehrdeutig; Mögliche Bedautung:" #: getopt.c:679 getopt.c:683 #, c-format @@ -2644,8 +2511,7 @@ msgstr "%s: Die Option »-W %s« erfordert ein Argument\n" #: io.c:392 #, c-format msgid "command line argument `%s' is a directory: skipped" -msgstr "" -"das Kommandozeilen-Argument »%s« ist ein Verzeichnis: wird übersprungen" +msgstr "das Kommandozeilen-Argument »%s« ist ein Verzeichnis: wird übersprungen" #: io.c:395 io.c:513 #, c-format @@ -2664,8 +2530,7 @@ msgstr "Umlenkungen sind im Sandbox-Modus nicht erlaubt" #: io.c:750 #, c-format msgid "expression in `%s' redirection only has numeric value" -msgstr "" -"Der Ausdruck in einer Umlenkung mittels »%s« hat nur einen numerischen Wert" +msgstr "Der Ausdruck in einer Umlenkung mittels »%s« hat nur einen numerischen Wert" #: io.c:756 #, c-format @@ -2675,9 +2540,7 @@ msgstr "Der Ausdruck für eine Umlenkung mittels »%s« ist ein leerer String" #: io.c:761 #, c-format msgid "filename `%s' for `%s' redirection may be result of logical expression" -msgstr "" -"Der Dateiname »%s« für eine Umlenkung mittels »%s« kann das Ergebnis eines " -"logischen Ausdrucks sein" +msgstr "Der Dateiname »%s« für eine Umlenkung mittels »%s« kann das Ergebnis eines logischen Ausdrucks sein" #: io.c:809 #, c-format @@ -2697,9 +2560,7 @@ msgstr "Die Pipe »%s« kann nicht für die Eingabe geöffnet werden (%s)" #: io.c:904 #, c-format msgid "can't open two way pipe `%s' for input/output (%s)" -msgstr "" -"Die bidirektionale Pipe »%s« kann nicht für die Ein-/Ausgabe geöffnet werden " -"(%s)" +msgstr "Die bidirektionale Pipe »%s« kann nicht für die Ein-/Ausgabe geöffnet werden (%s)" #: io.c:986 #, c-format @@ -2712,11 +2573,8 @@ msgid "can't redirect to `%s' (%s)" msgstr "Zu »%s« kann nicht umgelenkt werden (%s)" #: io.c:1040 -msgid "" -"reached system limit for open files: starting to multiplex file descriptors" -msgstr "" -"Die Systemgrenze offener Dateien ist erreicht, daher werden nun " -"Dateideskriptoren mehrfach verwendet" +msgid "reached system limit for open files: starting to multiplex file descriptors" +msgstr "Die Systemgrenze offener Dateien ist erreicht, daher werden nun Dateideskriptoren mehrfach verwendet" #: io.c:1056 #, c-format @@ -2743,9 +2601,7 @@ msgstr "»close« für eine Umlenkung, die nie geöffnet wurde" #: io.c:1205 #, c-format msgid "close: redirection `%s' not opened with `|&', second argument ignored" -msgstr "" -"close: Umlenkung »%s« wurde nicht mit »[&« geöffnet, das zweite Argument " -"wird ignoriert" +msgstr "close: Umlenkung »%s« wurde nicht mit »[&« geöffnet, das zweite Argument wird ignoriert" #: io.c:1222 #, c-format @@ -2842,8 +2698,7 @@ msgstr "»%s« konnte nicht geöffnet werden, Modus »%s«" #: io.c:1917 #, c-format msgid "close of master pty failed (%s)" -msgstr "" -"Das Schließen der übergeordneten Terminal-Gerätedatei ist gescheitert (%s)" +msgstr "Das Schließen der übergeordneten Terminal-Gerätedatei ist gescheitert (%s)" #: io.c:1919 io.c:2105 io.c:2305 #, c-format @@ -2853,9 +2708,7 @@ msgstr "Das Schließen der Standardausgabe im Kindprozess ist gescheitert (%s)" #: io.c:1922 #, c-format msgid "moving slave pty to stdout in child failed (dup: %s)" -msgstr "" -"Das Verschieben der untergeordneten Terminal-Gerätedatei zur Standardausgabe " -"im Kindprozess ist gescheitert (dup: %s)" +msgstr "Das Verschieben der untergeordneten Terminal-Gerätedatei zur Standardausgabe im Kindprozess ist gescheitert (dup: %s)" #: io.c:1924 io.c:2110 #, c-format @@ -2865,39 +2718,30 @@ msgstr "Schließen von stdin im Kindprozess gescheitert (%s)" #: io.c:1927 #, c-format msgid "moving slave pty to stdin in child failed (dup: %s)" -msgstr "" -"Das Verschieben der untergeordneten Terminal-Gerätedatei zur Standardeingabe " -"im Kindprozess ist gescheitert (dup: %s)" +msgstr "Das Verschieben der untergeordneten Terminal-Gerätedatei zur Standardeingabe im Kindprozess ist gescheitert (dup: %s)" #: io.c:1929 io.c:1951 #, c-format msgid "close of slave pty failed (%s)" -msgstr "" -"Das Schließen der untergeordneten Terminal-Gerätedatei ist gescheitert (%s)" +msgstr "Das Schließen der untergeordneten Terminal-Gerätedatei ist gescheitert (%s)" #: io.c:2040 io.c:2108 io.c:2276 io.c:2308 #, c-format msgid "moving pipe to stdout in child failed (dup: %s)" -msgstr "" -"Das Verschieben der Pipe zur Standardausgabe im Kindprozess ist gescheitert " -"(dup: %s)" +msgstr "Das Verschieben der Pipe zur Standardausgabe im Kindprozess ist gescheitert (dup: %s)" #: io.c:2047 io.c:2113 #, c-format msgid "moving pipe to stdin in child failed (dup: %s)" -msgstr "" -"Das Verschieben der Pipe zur Standardeingabe im Kindprozess ist gescheitert " -"(dup: %s)" +msgstr "Das Verschieben der Pipe zur Standardeingabe im Kindprozess ist gescheitert (dup: %s)" #: io.c:2073 io.c:2298 msgid "restoring stdout in parent process failed\n" -msgstr "" -"Das Wiederherstellen der Standardausgabe im Elternprozess ist gescheitert\n" +msgstr "Das Wiederherstellen der Standardausgabe im Elternprozess ist gescheitert\n" #: io.c:2081 msgid "restoring stdin in parent process failed\n" -msgstr "" -"Das Wiederherstellen der Standardeingabe im Elternprozess ist gescheitert\n" +msgstr "Das Wiederherstellen der Standardeingabe im Elternprozess ist gescheitert\n" #: io.c:2116 io.c:2310 io.c:2324 #, c-format @@ -2920,48 +2764,45 @@ msgstr "Kindprozess für »%s« kann nicht erzeugt werden (fork: %s)" #: io.c:2790 msgid "register_input_parser: received NULL pointer" -msgstr "" +msgstr "register_input_parser: NULL-Zeiger erhalten" #: io.c:2818 #, c-format msgid "input parser `%s' conflicts with previously installed input parser `%s'" -msgstr "" +msgstr "Eingabeparser »%s« steht im Konflikt mit dem vorher installierten Eingabeparser »%s«" #: io.c:2825 #, c-format msgid "input parser `%s' failed to open `%s'" -msgstr "" +msgstr "Eingabeparser »%s« konnte »%s« nicht öffnen" #: io.c:2845 msgid "register_output_wrapper: received NULL pointer" -msgstr "" +msgstr "register_output_wrapper: NULL-Zeiger erhalten" #: io.c:2873 #, c-format -msgid "" -"output wrapper `%s' conflicts with previously installed output wrapper `%s'" -msgstr "" +msgid "output wrapper `%s' conflicts with previously installed output wrapper `%s'" +msgstr "Ausgabeverpackung »%s« steht im Konflikt mit Ausgabeverpackung »%s«" #: io.c:2880 #, c-format msgid "output wrapper `%s' failed to open `%s'" -msgstr "" +msgstr "Ausgabeverpackung »%s« konnte »%s« nicht öffnen" #: io.c:2901 msgid "register_output_processor: received NULL pointer" -msgstr "" +msgstr "register_output_processor: NULL-Zeiger erhalten" #: io.c:2930 #, c-format -msgid "" -"two-way processor `%s' conflicts with previously installed two-way processor " -"`%s'" -msgstr "" +msgid "two-way processor `%s' conflicts with previously installed two-way processor `%s'" +msgstr "Zweiwegeprozessor »%s« steht im Konflikt mit Zweiwegeprozessor »%s«" #: io.c:2939 #, c-format msgid "two way processor `%s' failed to open `%s'" -msgstr "" +msgstr "Zweiwegeprozessor »%s« konnte »%s« nicht öffnen" #: io.c:3064 #, c-format @@ -2996,9 +2837,7 @@ msgstr "%s: Die Option %c erfordert ein Argument\n" #: main.c:562 msgid "environment variable `POSIXLY_CORRECT' set: turning on `--posix'" -msgstr "" -"Die Umgebungsvariable »POSIXLY_CORRECT« ist gesetzt: »--posix« wird " -"eingeschaltet" +msgstr "Die Umgebungsvariable »POSIXLY_CORRECT« ist gesetzt: »--posix« wird eingeschaltet" #: main.c:568 msgid "`--posix' overrides `--traditional'" @@ -3014,28 +2853,23 @@ msgid "running %s setuid root may be a security problem" msgstr "%s als setuid root auszuführen kann zu Sicherheitsproblemen führen" #: main.c:588 -#, fuzzy msgid "`--posix' overrides `--characters-as-bytes'" -msgstr "»--posix« hat Vorrang vor »--binary«" +msgstr "»--posix« hat Vorrang vor »--characters-as-bytes«" #: main.c:647 #, c-format msgid "can't set binary mode on stdin (%s)" -msgstr "" -"Das Setzen des Binärermodus für die Standardeingabe ist nicht möglich (%s)" +msgstr "Das Setzen des Binärermodus für die Standardeingabe ist nicht möglich (%s)" #: main.c:650 #, c-format msgid "can't set binary mode on stdout (%s)" -msgstr "" -"Das Setzen des Binärermodus für die Standardausgabe ist nicht möglich (%s)" +msgstr "Das Setzen des Binärermodus für die Standardausgabe ist nicht möglich (%s)" #: main.c:652 #, c-format msgid "can't set binary mode on stderr (%s)" -msgstr "" -"Das Setzen des Binärermodus für die Standardfehlerausgabe ist nicht möglich " -"(%s)" +msgstr "Das Setzen des Binärermodus für die Standardfehlerausgabe ist nicht möglich (%s)" #: main.c:710 msgid "no program text at all!" @@ -3088,9 +2922,8 @@ msgid "\t-d[file]\t\t--dump-variables[=file]\n" msgstr "\t-d [Datei]\t\t--dump-variables[=Datei]\n" #: main.c:815 -#, fuzzy msgid "\t-D[file]\t\t--debug[=file]\n" -msgstr "\t-p [Datei]\t\t--profile[=Datei]\n" +msgstr "\t-D[Datei]\t\t--debug[=Datei]\n" #: main.c:816 msgid "\t-e 'program-text'\t--source='program-text'\n" @@ -3110,11 +2943,11 @@ msgstr "\t-h\t\t\t--help\n" #: main.c:820 msgid "\t-i includefile\t\t--include=includefile\n" -msgstr "" +msgstr "\t-i einzubindende_datei\t\t--include=einzubindende_datei\n" #: main.c:821 msgid "\t-l library\t\t--load=library\n" -msgstr "" +msgstr "\t-l Bibliothek\t\t--load=Bibliothek\n" #: main.c:822 msgid "\t-L [fatal]\t\t--lint[=fatal]\n" @@ -3125,18 +2958,16 @@ msgid "\t-n\t\t\t--non-decimal-data\n" msgstr "\t-n\t\t\t--non-decimal-data\n" #: main.c:824 -#, fuzzy msgid "\t-M\t\t\t--bignum\n" -msgstr "\t-g\t\t\t--gen-pot\n" +msgstr "\t-M\t\t\t--bignum\n" #: main.c:825 msgid "\t-N\t\t\t--use-lc-numeric\n" msgstr "\t-N\t\t\t--use-lc-numeric\n" #: main.c:826 -#, fuzzy msgid "\t-o[file]\t\t--pretty-print[=file]\n" -msgstr "\t-p [Datei]\t\t--profile[=Datei]\n" +msgstr "\t-o[Datei]\t\t--pretty-print[=Datei]\n" #: main.c:827 msgid "\t-O\t\t\t--optimize\n" @@ -3191,8 +3022,8 @@ msgstr "" "in »gawk.info«, den Sie als Kapitel »Reporting Problems and Bugs«\n" "in der gedruckten Version finden.\n" "\n" -"Fehler in der Übersetzuung senden Sie bitte als E-Mail an\n" -"an translation-team-de@lists.sourceforge.net\n" +"Fehler in der Übersetzung senden Sie bitte als E-Mail an\n" +"translation-team-de@lists.sourceforge.net\n" "\n" #: main.c:851 @@ -3289,8 +3120,7 @@ msgstr "»%s« ist kein Variablenname, es wird nach der Datei »%s=%s« gesucht" #: main.c:1339 #, c-format msgid "cannot use gawk builtin `%s' as variable name" -msgstr "" -"die eingebaute Funktion »%s« kann nicht als Variablenname verwendet werden" +msgstr "die eingebaute Funktion »%s« kann nicht als Variablenname verwendet werden" # c-format #: main.c:1344 @@ -3325,58 +3155,54 @@ msgid "could not pre-open /dev/null for fd %d" msgstr "/dev/null konnte nicht für Dateideskriptor %d geöffnet werden" #: mpfr.c:550 -#, fuzzy, c-format +#, c-format msgid "PREC value `%.*s' is invalid" -msgstr "BINMODE Wert »%s« ist ungültig und wird als 3 behandelt" +msgstr "PREC Wert »%.*s« ist ungültig" #: mpfr.c:608 -#, fuzzy, c-format +#, c-format msgid "RNDMODE value `%.*s' is invalid" -msgstr "BINMODE Wert »%s« ist ungültig und wird als 3 behandelt" +msgstr "BINMODE Wert »%.*s« ist ungültig" #: mpfr.c:698 -#, fuzzy, c-format +#, c-format msgid "%s: received non-numeric argument" -msgstr "cos: das Argument ist keine Zahl" +msgstr "%s: das Argument ist keine Zahl" #: mpfr.c:800 -#, fuzzy msgid "compl(%Rg): negative value will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "compl(%Rg): ein negativer Wert wird zu merkwürdigen Ergebnissen führen" #: mpfr.c:804 -#, fuzzy msgid "comp(%Rg): fractional value will be truncated" -msgstr "compl(%lf): Dezimalteil wird abgeschnitten" +msgstr "compl(%Rg): Dezimalteil wird abgeschnitten" #: mpfr.c:816 -#, fuzzy, c-format +#, c-format msgid "cmpl(%Zd): negative values will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "cmpl(%Zd): Negative Werte führen zu merkwürdigen Ergebnissen" #: mpfr.c:835 -#, fuzzy, c-format +#, c-format msgid "%s: received non-numeric argument #%d" -msgstr "cos: das Argument ist keine Zahl" +msgstr "%s: das Argument Nr. %d ist keine Zahl" #: mpfr.c:845 msgid "%s: argument #%d has invalid value %Rg, using 0" -msgstr "" +msgstr "%s: Argument Nr. %d hat den ungültigen Wert %Rg, es wird stattdessen 0 verwendet" #: mpfr.c:857 -#, fuzzy msgid "%s: argument #%d negative value %Rg will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "%s: der negative Wert %2$Rg in Argument Nr. %1$d wird zu merkwürdigen Ergebnissen führen" #: mpfr.c:863 -#, fuzzy msgid "%s: argument #%d fractional value %Rg will be truncated" -msgstr "or(%lf, %lf): Dezimalteil wird abgeschnitten" +msgstr "%s: der Nachkommateil %2$Rg in Argument Nr. %1$d wird abgeschnitten" #: mpfr.c:878 -#, fuzzy, c-format +#, c-format msgid "%s: argument #%d negative value %Zd will give strange results" -msgstr "compl(%lf): Negativer Wert wird zu merkwürdigen Ergebnissen führen" +msgstr "%1$s: der negative Wert %3$Zd in Argument Nr. %2$d wird zu merkwürdigen Ergebnissen führen" #: msg.c:68 #, c-format @@ -3390,7 +3216,7 @@ msgstr "Backslash am Ende der Zeichenkette" #: node.c:500 #, c-format msgid "old awk does not support the `\\%c' escape sequence" -msgstr "Das alte awk unterstützt die Fluchsequenz »\\%c« nicht" +msgstr "Das alte awk unterstützt die Escapesequenz »\\%c« nicht" #: node.c:551 msgid "POSIX does not allow `\\x' escapes" @@ -3402,12 +3228,8 @@ msgstr "In der »\\x«-Fluchtsequenz sind keine hexadezimalen Zahlen" #: node.c:579 #, c-format -msgid "" -"hex escape \\x%.*s of %d characters probably not interpreted the way you " -"expect" -msgstr "" -"Die Hex-Sequenz \\x%.*s aus %d Zeichen wird wahrscheinlich nicht wie " -"gewünscht interpretiert" +msgid "hex escape \\x%.*s of %d characters probably not interpreted the way you expect" +msgstr "Die Hex-Sequenz \\x%.*s aus %d Zeichen wird wahrscheinlich nicht wie gewünscht interpretiert" #: node.c:594 #, c-format @@ -3415,25 +3237,18 @@ msgid "escape sequence `\\%c' treated as plain `%c'" msgstr "Fluchtsequenz »\\%c« wird wie ein normales »%c« behandelt" #: node.c:739 -msgid "" -"Invalid multibyte data detected. There may be a mismatch between your data " -"and your locale." -msgstr "" -"Es wurden unbekannte Multibyte-Daten gefunden. Ihre Daten entsprechen " -"neventuell nicht der gesetzten Locale" +msgid "Invalid multibyte data detected. There may be a mismatch between your data and your locale." +msgstr "Es wurden unbekannte Multibyte-Daten gefunden. Ihre Daten entsprechen neventuell nicht der gesetzten Locale" #: posix/gawkmisc.c:177 #, c-format msgid "%s %s `%s': could not get fd flags: (fcntl F_GETFD: %s)" -msgstr "" -"%s %s »%s«: Die Kennungen des Dateideskriptors konnten nicht abgefragt " -"werden: (fcntl F_GETFD: %s)" +msgstr "%s %s »%s«: Die Kennungen des Dateideskriptors konnten nicht abgefragt werden: (fcntl F_GETFD: %s)" #: posix/gawkmisc.c:189 #, c-format msgid "%s %s `%s': could not set close-on-exec: (fcntl F_SETFD: %s)" -msgstr "" -"%s %s »%s«: close-on-exec konnte nicht gesetzt werden: (fcntl F_SETFD: %s)" +msgstr "%s %s »%s«: close-on-exec konnte nicht gesetzt werden: (fcntl F_SETFD: %s)" #: profile.c:71 #, c-format @@ -3468,9 +3283,8 @@ msgid "internal error: %s with null vname" msgstr "Interner Fehler: %s mit null vname" #: profile.c:537 -#, fuzzy msgid "internal error: builtin with null fname" -msgstr "Interner Fehler: %s mit null vname" +msgstr "Interner Fehler: eingebaute Fuktion mit leerem fname" #: profile.c:949 #, c-format @@ -3478,6 +3292,8 @@ msgid "" "\t# Loaded extensions (-l and/or @load)\n" "\n" msgstr "" +"\t# Erweiterungen geladen (-l und/oder @load)\n" +"\n" #: profile.c:972 #, c-format @@ -3501,8 +3317,7 @@ msgstr "redir2str: unbekannter Umlenkungstyp %d" #: re.c:607 #, c-format msgid "regexp component `%.*s' should probably be `[%.*s]'" -msgstr "" -"Regulärer-Ausdruck-Komponente »%.*s« sollte wahrscheinlich »[%.*s]« sein" +msgstr "Regulärer-Ausdruck-Komponente »%.*s« sollte wahrscheinlich »[%.*s]« sein" #: regcomp.c:131 msgid "Success" @@ -3570,148 +3385,4 @@ msgstr "Kein vorangehender regulärer Ausdruck" #: symbol.c:741 msgid "can not pop main context" -msgstr "" - -#~ msgid "range of the form `[%c-%c]' is locale dependent" -#~ msgstr "" -#~ "Ein Bereich in der Form »[%c-%c]« ist abhängig von der gesetzten Locale" - -#, fuzzy -#~ msgid "[s]printf called with no arguments" -#~ msgstr "sqrt: das Argument %g ist negativ" - -#~ msgid "`-m[fr]' option irrelevant in gawk" -#~ msgstr "Die Option »-m[fr]« ist in gawk bedeutungslos" - -#~ msgid "-m option usage: `-m[fr] nnn'" -#~ msgstr "Anwendung der Option -m: »-m[fr] nnn«" - -#, fuzzy -#~ msgid "%s: received non-numeric first argument" -#~ msgstr "or: das erste Argument ist keine Zahl" - -#, fuzzy -#~ msgid "%s: received non-numeric second argument" -#~ msgstr "or: das zweite Argument ist keine Zahl" - -#, fuzzy -#~ msgid "%s(%Rg, ..): negative values will give strange results" -#~ msgstr "" -#~ "or(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" - -#, fuzzy -#~ msgid "%s(%Rg, ..): fractional values will be truncated" -#~ msgstr "or(%lf, %lf): Dezimalteil wird abgeschnitten" - -#, fuzzy -#~ msgid "%s(%Zd, ..): negative values will give strange results" -#~ msgstr "" -#~ "or(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" - -#, fuzzy -#~ msgid "%s(.., %Rg): negative values will give strange results" -#~ msgstr "" -#~ "or(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" - -#, fuzzy -#~ msgid "%s(.., %Zd): negative values will give strange results" -#~ msgstr "" -#~ "or(%lf, %lf): Negative Werte werden zu merkwürdigen Ergebnissen führen" - -#~ msgid "`%s' is a Bell Labs extension" -#~ msgstr "»%s« ist eine Erweiterung der Bell Labs" - -#~ msgid "`nextfile' is a gawk extension" -#~ msgstr "»nextfile« ist eine gawk-Erweiterung" - -#~ msgid "`delete array' is a gawk extension" -#~ msgstr "»delete array« ist eine gawk-Erweiterung" - -#~ msgid "and: received non-numeric first argument" -#~ msgstr "and: das erste Argument ist keine Zahl" - -#~ msgid "and: received non-numeric second argument" -#~ msgstr "and: das zweite Argument ist keine Zahl" - -#~ msgid "and(%lf, %lf): fractional values will be truncated" -#~ msgstr "and(%lf, %lf): Dezimalteil wird abgeschnitten" - -#~ msgid "xor: received non-numeric first argument" -#~ msgstr "xor: das erste Argument ist keine Zahl" - -#~ msgid "xor: received non-numeric second argument" -#~ msgstr "xor: das zweite Argument ist keine Zahl" - -#~ msgid "xor(%lf, %lf): fractional values will be truncated" -#~ msgstr "xor(%lf, %lf): Dezimalteil wird abgeschnitten" - -#~ msgid "Operation Not Supported" -#~ msgstr "Die Operation wird nicht unterstützt" - -#~ msgid "attempt to use function `%s' as an array" -#~ msgstr "Es wird versucht, die Funktion »%s« als Feld zu verwenden" - -#~ msgid "reference to uninitialized element `%s[\"%.*s\"]'" -#~ msgstr "Bezug auf ein nicht initialisiertes Element »%s[\"%.*s\"]«" - -#~ msgid "subscript of array `%s' is null string" -#~ msgstr "Der Index von Feld »%s« ist ein Nullstring" - -#~ msgid "%s: empty (null)\n" -#~ msgstr "%s: leer (Null)\n" - -#~ msgid "%s: empty (zero)\n" -#~ msgstr "%s: leer (0)\n" - -#~ msgid "%s: table_size = %d, array_size = %d\n" -#~ msgstr "%s: Tabellengröße = %d, Feldgröße = %d\n" - -#~ msgid "%s: array_ref to %s\n" -#~ msgstr "%s: Feld-Referenz auf %s\n" - -#~ msgid "use of non-array as array" -#~ msgstr "Verwendung eines Nicht-Feldes als Feld" - -#~ msgid "can't use function name `%s' as variable or array" -#~ msgstr "Funktion »%s« kann nicht als Variable oder Feld verwendet werden" - -#~ msgid "assignment used in conditional context" -#~ msgstr "Zuweisung in einer Bedingung" - -#~ msgid "statement has no effect" -#~ msgstr "Anweisung hat keinen Effekt" - -#~ msgid "" -#~ "for loop: array `%s' changed size from %ld to %ld during loop execution" -#~ msgstr "" -#~ "for-Schleife: Feld »%s« ändert seine Größe von %ld innerhalb der Schleife " -#~ "zu %ld" - -#~ msgid "function called indirectly through `%s' does not exist" -#~ msgstr "die durch »%s« indirekt aufgerufene Funktion existiert nicht" - -#~ msgid "function `%s' not defined" -#~ msgstr "Funktion »%s« ist nicht definiert" - -#~ msgid "non-redirected `getline' invalid inside `%s' rule" -#~ msgstr "Nicht umgelenktes »getline« ist innerhalb der »%s«-Aktion unzuässig" - -#~ msgid "`nextfile' cannot be called from a `%s' rule" -#~ msgstr "»nextfile« kann nicht aus einer »«%s-Regel aufgerufen werden" - -#~ msgid "`next' cannot be called from a `%s' rule" -#~ msgstr "»next« kann nicht in einer »%s«-Regel verwendet werden" - -#~ msgid "Sorry, don't know how to interpret `%s'" -#~ msgstr "" -#~ "Entschuldigung, aber es ist unbekannt, wie »%s« zu interpretieren ist" - -#~ msgid "\t-R file\t\t\t--command=file\n" -#~ msgstr "\t-R Datei\t\t\t--command=Datei\n" - -#~ msgid "could not find groups: %s" -#~ msgstr "Die Gruppen konnten nicht gefunden werden: %s" - -#~ msgid "assignment is not allowed to result of builtin function" -#~ msgstr "" -#~ "Zuweisungen an das Ergebnis einer eingebauten Funktion sind nicht erlaubt" +msgstr "der Hauptkontext kann nicht entfernt werden" Binary files differ@@ -1,17 +1,18 @@ # Swedish translation of gawk # Copyright © 2003, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. # This file is distributed under the same license as the gawk package. +# # Martin Sjögren <md9ms@mdstud.chalmers.se>, 2001-2002. # Christer Andersson <klamm@comhem.se>, 2007. # Göran Uddeborg <goeran@uddeborg.se>, 2011, 2012, 2013, 2014. # -# $Revision: 1.14 $ +# $Revision: 1.15 $ msgid "" msgstr "" "Project-Id-Version: gawk 4.1.0b\n" "Report-Msgid-Bugs-To: arnold@skeeve.com\n" "POT-Creation-Date: 2014-04-08 19:23+0300\n" -"PO-Revision-Date: 2014-01-21 17:40+0100\n" +"PO-Revision-Date: 2014-09-22 09:12+0200\n" "Last-Translator: Göran Uddeborg <goeran@uddeborg.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -690,7 +691,7 @@ msgstr "^ tog slut här" #: builtin.c:1575 msgid "[s]printf: format specifier does not have control letter" -msgstr "[s]printf: formatspecifieraren har ingen kommandobokstav" +msgstr "[s]printf: formatspecificeraren har ingen kommandobokstav" #: builtin.c:1578 msgid "too many arguments supplied for format string" @@ -770,7 +771,7 @@ msgstr "strftime: fick ett ickenumeriskt andra argument" #: builtin.c:1927 msgid "strftime: second argument less than 0 or too big for time_t" -msgstr "strftime: andra argimentet mindre än 0 eller för stort för time_t" +msgstr "strftime: andra argumentet mindre än 0 eller för stort för time_t" #: builtin.c:1934 msgid "strftime: received non-string first argument" @@ -899,7 +900,7 @@ msgstr "and: argument %d med negativt värde %g kommer ge konstiga resultat" #: builtin.c:3136 mpfr.c:1000 msgid "or: called with less than two arguments" -msgstr "or: anropad med färre än två argmuent" +msgstr "or: anropad med färre än två argument" #: builtin.c:3141 #, c-format @@ -1087,7 +1088,7 @@ msgstr "delete [brytpunkter] [intervall] - radera angivna brytpunkter." #: command.y:831 msgid "disable [breakpoints] [range] - disable specified breakpoints." -msgstr "disable [brytpunkger] [intervall] - avaktivera angivna brytpunkter." +msgstr "disable [brytpunkter] [intervall] - avaktivera angivna brytpunkter." #: command.y:833 msgid "display [var] - print value of variable each time the program stops." @@ -1277,7 +1278,7 @@ msgstr "odefinierat kommando: %s\n" #: debug.c:252 msgid "set or show the number of lines to keep in history file." -msgstr "sätt eller visa antalet rader att behålla i historiefilen." +msgstr "sätt eller visa antalet rader att behålla i historikfilen." #: debug.c:254 msgid "set or show the list command window size." @@ -1293,7 +1294,7 @@ msgstr "sätt eller visa felsökningsprompten." #: debug.c:260 msgid "(un)set or show saving of command history (value=on|off)." -msgstr "slå av/på eller visa sparandet av kommandohisterik (värde=on|off)." +msgstr "slå av/på eller visa sparandet av kommandohistorik (värde=on|off)." #: debug.c:262 msgid "(un)set or show saving of options (value=on|off)." @@ -1561,7 +1562,7 @@ msgstr "Ogiltigt ramnummer" #, c-format msgid "Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d" msgstr "" -"Observera: brytpunkt %d (aktiverad, ingorera följande %ld träffar), är också " +"Observera: brytpunkt %d (aktiverad, ignorera följande %ld träffar), är också " "satt vid %s:%d" #: debug.c:2207 @@ -1604,7 +1605,7 @@ msgstr "Kan inte hitta regeln!!!\n" #: debug.c:2375 #, c-format msgid "Can't set breakpoint at `%s':%d\n" -msgstr "Kan inte sätta än brytpunkt vid ”%s”:%d\n" +msgstr "Kan inte sätta en brytpunkt vid ”%s”:%d\n" #: debug.c:2387 #, c-format @@ -1680,7 +1681,7 @@ msgstr "fel: kan inte starta om, åtgärden är inte tillåten\n" #: debug.c:2942 #, c-format msgid "error (%s): cannot restart, ignoring rest of the commands\n" -msgstr "fel (%s): kan inte starta om, ingorerar resten av kommandona\n" +msgstr "fel (%s): kan inte starta om, ignorerar resten av kommandona\n" #: debug.c:2950 #, c-format @@ -2824,11 +2825,11 @@ msgstr "flyttande av rör till standard in i barnet misslyckades (dup: %s)" #: io.c:2073 io.c:2298 msgid "restoring stdout in parent process failed\n" -msgstr "återställande av standard ut i förälderprocessen misslyckades\n" +msgstr "återställande av standard ut i föräldraprocessen misslyckades\n" #: io.c:2081 msgid "restoring stdin in parent process failed\n" -msgstr "återställande av standard in i förälderprocessen misslyckades\n" +msgstr "återställande av standard in i föräldraprocessen misslyckades\n" #: io.c:2116 io.c:2310 io.c:2324 #, c-format @@ -2880,7 +2881,7 @@ msgstr "" #: io.c:2880 #, c-format msgid "output wrapper `%s' failed to open `%s'" -msgstr "utmatningsomslag ”%s” misslyckades att öpnna ”%s”" +msgstr "utmatningsomslag ”%s” misslyckades att öppna ”%s”" #: io.c:2901 msgid "register_output_processor: received NULL pointer" @@ -3180,7 +3181,7 @@ msgid "" "along with this program. If not, see http://www.gnu.org/licenses/.\n" msgstr "" "Du bör ha fått en kopia av GNU General Public License tillsammans\n" -"med detta program. Om inte, se http//www.gnu.org/liceences/.\n" +"med detta program. Om inte, se http://www.gnu.org/licenses/.\n" #: main.c:931 msgid "-Ft does not set FS to tab in POSIX awk" @@ -36,7 +36,8 @@ static bool is_scalar(int type); static int prec_level(int type); static void pp_push(int type, char *s, int flag); static NODE *pp_pop(void); -static void pp_free(NODE *n); +static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header); +static void print_comment(INSTRUCTION *pc, long in); const char *redir2str(int redirtype); #define pp_str vname @@ -100,10 +101,12 @@ indent(long count) { int i; - if (count == 0) - fprintf(prof_fp, "\t"); - else - fprintf(prof_fp, "%6ld ", count); + if (do_profile) { + if (count == 0) + fprintf(prof_fp, "\t"); + else + fprintf(prof_fp, "%6ld ", count); + } assert(indent_level >= 0); for (i = 0; i < indent_level; i++) @@ -177,6 +180,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header) NODE *m; char *tmp; int rule; + long lind; static int rule_count[MAXRULE]; for (pc = startp; pc != endp; pc = pc->nexti) { @@ -189,16 +193,35 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header) rule = pc->in_rule; if (rule != Rule) { - if (! rule_count[rule]++) - fprintf(prof_fp, _("\t# %s block(s)\n\n"), ruletab[rule]); - fprintf(prof_fp, "\t%s {\n", ruletab[rule]); ip = (pc + 1)->firsti; + + /* print pre-begin/end comments */ + if (ip->opcode == Op_comment) { + print_comment(ip, 0); + ip = ip->nexti; + } + + if (do_profile) { + if (! rule_count[rule]++) + fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]); + indent(0); + } + fprintf(prof_fp, "%s {\n", ruletab[rule]); } else { - if (! rule_count[rule]++) + if (do_profile && ! rule_count[rule]++) fprintf(prof_fp, _("\t# Rule(s)\n\n")); ip = pc->nexti; - indent(ip->exec_count); + lind = ip->exec_count; + /* print pre-block comments */ + if (ip->opcode == Op_exec_count && ip->nexti->opcode == Op_comment) + ip = ip->nexti; + if (ip->opcode == Op_comment) { + print_comment(ip, lind); + if (ip->nexti->nexti == (pc + 1)->firsti) + ip = ip->nexti->nexti; + } if (ip != (pc + 1)->firsti) { /* non-empty pattern */ + indent(lind); pprint(ip->nexti, (pc + 1)->firsti, false); t1 = pp_pop(); fprintf(prof_fp, "%s {", t1->pp_str); @@ -218,7 +241,9 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header) indent_in(); pprint(ip, (pc + 1)->lasti, false); indent_out(); - fprintf(prof_fp, "\t}\n\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "}\n\n"); pc = (pc + 1)->lasti; break; @@ -395,7 +420,8 @@ cleanup: case Op_unary_minus: case Op_not: t1 = pp_pop(); - if (is_binary(t1->type)) + if (is_binary(t1->type) + || (((OPCODE) t1->type) == pc->opcode && pc->opcode == Op_unary_minus)) pp_parenthesize(t1); /* optypes table (eval.c) includes space after ! */ @@ -881,6 +907,13 @@ cleanup: indent(pc->exec_count); break; + case Op_comment: + print_comment(pc, 0); + break; + + case Op_list: + break; + default: cant_happen(); } @@ -909,11 +942,11 @@ pp_string_fp(Func_print print_func, FILE *fp, const char *in_str, slen = strlen(str); for (count = 0; slen > 0; slen--, str++) { + print_func(fp, "%c", *str); if (++count >= BREAKPOINT && breaklines) { print_func(fp, "%c\n%c", delim, delim); count = 0; - } else - print_func(fp, "%c", *str); + } } efree(s); } @@ -963,6 +996,30 @@ print_lib_list(FILE *prof_fp) fprintf(prof_fp, "\n"); } +/* print_comment --- print comment text with proper indentation */ + +static void +print_comment(INSTRUCTION* pc, long in) +{ + char *text; + size_t count; + bool after_newline = false; + + count = pc->memory->stlen; + text = pc->memory->stptr; + + indent(in); /* is this correct? Where should comments go? */ + for (; count > 0; count--, text++) { + if (after_newline) { + indent(in); + after_newline = false; + } + putc(*text, prof_fp); + if (*text == '\n') + after_newline = true; + } +} + /* dump_prog --- dump the program */ /* @@ -977,7 +1034,8 @@ dump_prog(INSTRUCTION *code) (void) time(& now); /* \n on purpose, with \n in ctime() output */ - fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now)); + if (do_profile) + fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now)); print_lib_list(prof_fp); pprint(code, NULL, false); } @@ -1000,25 +1058,25 @@ prec_level(int type) case Op_func_call: case Op_K_delete_loop: case Op_builtin: - return 15; + return 16; case Op_field_spec: case Op_field_spec_lhs: - return 14; - - case Op_exp: - case Op_exp_i: - return 13; + return 15; case Op_preincrement: case Op_predecrement: case Op_postincrement: case Op_postdecrement: - return 12; + return 14; + + case Op_exp: + case Op_exp_i: + return 13; case Op_unary_minus: case Op_not: - return 11; + return 12; case Op_times: case Op_times_i: @@ -1026,23 +1084,26 @@ prec_level(int type) case Op_quotient_i: case Op_mod: case Op_mod_i: - return 10; + return 11; case Op_plus: case Op_plus_i: case Op_minus: case Op_minus_i: - return 9; + return 10; case Op_concat: case Op_assign_concat: - return 8; + return 9; case Op_equal: case Op_notequal: case Op_greater: + case Op_less: case Op_leq: case Op_geq: + return 8; + case Op_match: case Op_nomatch: return 7; @@ -1051,7 +1112,6 @@ prec_level(int type) case Op_K_getline_redir: return 6; - case Op_less: case Op_in_array: return 5; @@ -1177,6 +1237,26 @@ pp_parenthesize(NODE *sp) sp->flags |= CAN_FREE; } +/* div_on_left_mul_on_right --- have / or % on left and * on right */ + +static bool +div_on_left_mul_on_right(int o1, int o2) +{ + OPCODE op1 = (OPCODE) o1; + OPCODE op2 = (OPCODE) o2; + + switch (op1) { + case Op_quotient: + case Op_quotient_i: + case Op_mod: + case Op_mod_i: + return (op2 == Op_times || op2 == Op_times_i); + + default: + return false; + } +} + /* parenthesize --- parenthesize two nodes relative to parent node type */ static void @@ -1186,9 +1266,11 @@ parenthesize(int type, NODE *left, NODE *right) int lprec = prec_level(left->type); int prec = prec_level(type); - if (lprec < prec) + if (lprec < prec + || (lprec == prec && div_on_left_mul_on_right(left->type, type))) pp_parenthesize(left); - if (rprec < prec) + if (rprec < prec + || (rprec == prec && div_on_left_mul_on_right(type, right->type))) pp_parenthesize(right); } @@ -1360,6 +1442,14 @@ pp_list(int nargs, const char *paren, const char *delim) return str; } +/* is_unary_minus --- return true if string starts with unary minus */ + +static bool +is_unary_minus(const char *str) +{ + return str[0] == '-' && str[1] != '-'; +} + /* pp_concat --- handle concatenation and correct parenthesizing of expressions */ static char * @@ -1401,7 +1491,12 @@ pp_concat(int nargs) pl_l = prec_level(pp_args[i]->type); pl_r = prec_level(pp_args[i+1]->type); - if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) { + if (i >= 2 && is_unary_minus(r->pp_str)) { + *s++ = '('; + memcpy(s, r->pp_str, r->pp_len); + s += r->pp_len; + *s++ = ')'; + } else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) { memcpy(s, r->pp_str, r->pp_len); s += r->pp_len; } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) { @@ -1423,7 +1518,7 @@ pp_concat(int nargs) pl_l = prec_level(pp_args[nargs-1]->type); pl_r = prec_level(pp_args[nargs]->type); r = pp_args[nargs]; - if (pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)) { + if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) { *s++ = '('; memcpy(s, r->pp_str, r->pp_len); s += r->pp_len; @@ -1477,14 +1572,24 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) static bool first = true; NODE *func; int pcount; + INSTRUCTION *fp; if (first) { first = false; - fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n")); + if (do_profile) + fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n")); } + fp = pc->nexti->nexti; func = pc->func_body; fprintf(prof_fp, "\n"); + + /* print any function comment */ + if (fp->opcode == Op_comment && fp->source_line == 0) { + print_comment(fp, 0); + fp = fp->nexti; + } + indent(pc->nexti->exec_count); fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname); pcount = func->param_cnt; @@ -1494,11 +1599,16 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) if (j < pcount - 1) fprintf(prof_fp, ", "); } - fprintf(prof_fp, ")\n\t{\n"); + fprintf(prof_fp, ")\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "{\n"); indent_in(); - pprint(pc->nexti->nexti, NULL, false); /* function body */ + pprint(fp, NULL, false); /* function body */ indent_out(); - fprintf(prof_fp, "\t}\n"); + if (do_profile) + indent(0); + fprintf(prof_fp, "}\n"); return 0; } @@ -284,13 +284,18 @@ research(Regexp *rp, char *str, int start, if (rp->dfa && ! no_bol && ! need_start) { char save; size_t count = 0; + struct dfa *superset = dfasuperset(rp->dfareg); /* * dfa likes to stick a '\n' right after the matched * text. So we just save and restore the character. */ save = str[start+len]; - ret = dfaexec(rp->dfareg, str+start, str+start+len, true, - &count, &try_backref); + if (superset) + ret = dfaexec(superset, str+start, str+start+len, + true, NULL, NULL); + if (ret) + ret = dfaexec(rp->dfareg, str+start, str+start+len, + true, &count, &try_backref); str[start+len] = save; } @@ -149,7 +149,7 @@ const char __re_error_msgid[] attribute_hidden = gettext_noop ("Invalid back reference") /* REG_ESUBREG */ "\0" #define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") - gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ + gettext_noop ("Unmatched [, [^, [:, [., or [=") /* REG_EBRACK */ "\0" #define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ diff --git a/test/ChangeLog b/test/ChangeLog index 8e89f0d2..9d49a888 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,8 +1,64 @@ +2014-11-02 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (profile7): New test. + (profile6): Add missing @ in front of gawk run. + * profile7.awk, profile7.ok: New files. + +2014-11-01 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (profile6): Actually run profiling. Should make test + output consistent with what's in master. + * profile6.ok: Updated. + +2014-10-30 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (profile6): New test. + * profile6.awk, profile6.ok: New files. + +2014-10-17 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (profile1, testext): Use explicit ./foo.awk to avoid + assumptions about AWKPATH in the environment. + +2014-10-12 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (charset-msg-start): Add a list of needed locales. + Suggested by Shaun Jackman <sjackman@gmail.com>. + +2014-10-05 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok, profile3.ok, profile4.ok, profile5.ok: + Adjusted after minor code change. Again. + +2014-10-04 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (genpot): New test. + * genpot.awk, genpot.ok: New files. + +2014-09-29 Arnold D. Robbins <arnold@skeeve.com> + + * testext.ok: Adjusted after minor code change. + +2014-09-27 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok, profile3.ok, profile4.ok, profile5.ok: + Adjusted after minor code change. + 2014-09-18 Arnold D. Robbins <arnold@skeeve.com> * filefuncs.awk: Change to build directory instead of "..". * Makefile.am (filefuncs): Pass in $(abs_top_builddir). +2014-09-13 Stephen Davies <sdavies@sdc.com.au> + + * Makefile.am (profile4, profile5): Changes processing to not delete + the first two lines. This is no longer needed. + * profile4.ok, profile5.ok: Changed to suit new rules and comments. + +2014-09-10 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok, profile4.ok, profile5.ok: Update for new code. + 2014-09-05 Arnold D. Robbins <arnold@skeeve.com> * functab4.awk: Changed to use stat instead of chdir since @@ -292,6 +348,10 @@ in locations with spaces in their names (think Windows or Mac OS X). * Gentests: Ditto for when creating Maketests file. +2013-07-30 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok, profile5.ok: Update. + 2013-07-04 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (mbprintf4): New test. diff --git a/test/Makefile.am b/test/Makefile.am index 1c14ea81..db1cb086 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -324,6 +324,8 @@ EXTRA_DIST = \ fwtest3.awk \ fwtest3.in \ fwtest3.ok \ + genpot.awk \ + genpot.ok \ gensub.awk \ gensub.in \ gensub.ok \ @@ -704,6 +706,10 @@ EXTRA_DIST = \ profile4.ok \ profile5.awk \ profile5.ok \ + profile6.awk \ + profile6.ok \ + profile7.awk \ + profile7.ok \ prt1eval.awk \ prt1eval.ok \ prtoeval.awk \ @@ -1009,7 +1015,7 @@ GAWK_EXT_TESTS = \ colonwarn clos1way dbugeval delsub devfd devfd1 devfd2 dumpvars exit \ fieldwdth fpat1 fpat2 fpat3 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ - gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ + genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ include include2 indirectcall indirectcall2 \ @@ -1017,7 +1023,7 @@ GAWK_EXT_TESTS = \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ patsplit posix printfbad1 printfbad2 printfbad3 printhuge procinfs \ - profile1 profile2 profile3 profile4 profile5 pty1 \ + profile1 profile2 profile3 profile4 profile5 profile6 profile7 pty1 \ rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \ rsstart2 rsstart3 rstest6 shadow sortfor sortu split_after_fpat \ splitarg4 strftime \ @@ -1166,6 +1172,8 @@ charset-msg-start: @echo "************************************************" @echo "** Some or all of these tests may fail if you **" @echo "** have inadequate or missing locale support **" + @echo "** At least en_US.UTF-8, ru_RU.UTF-8 and **" + @echo "** ja_JP.UTF-8 are needed. **" @echo "************************************************" charset-msg-end: @@ -1669,7 +1677,7 @@ profile1: @echo $@ @$(AWK) -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1 @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk - @$(AWK) -f ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out + @$(AWK) -f ./ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out @$(CMP) _$@.out1 _$@.out2 && rm _$@.out[12] || { echo EXIT CODE: $$? >>_$@ ; \ cp "$(srcdir)"/dtdgport.awk $@.ok ; } @@ -1688,13 +1696,23 @@ profile3: profile4: @echo $@ - @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null - @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out + @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ profile5: @echo $@ - @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null + @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +profile6: + @echo $@ + @$(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null + @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +profile7: + @echo $@ + @$(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @@ -1860,7 +1878,7 @@ inplace3:: testext:: @echo $@ @$(AWK) '/^(@load|BEGIN)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk - @$(AWK) -f testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk readdir: @@ -1977,6 +1995,11 @@ filefuncs: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk -v builddir="$(abs_top_builddir)" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +genpot: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --gen-pot >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + # Targets generated for other tests: include Maketests diff --git a/test/Makefile.in b/test/Makefile.in index b7e25511..ab8aebe3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -570,6 +570,8 @@ EXTRA_DIST = \ fwtest3.awk \ fwtest3.in \ fwtest3.ok \ + genpot.awk \ + genpot.ok \ gensub.awk \ gensub.in \ gensub.ok \ @@ -950,6 +952,10 @@ EXTRA_DIST = \ profile4.ok \ profile5.awk \ profile5.ok \ + profile6.awk \ + profile6.ok \ + profile7.awk \ + profile7.ok \ prt1eval.awk \ prt1eval.ok \ prtoeval.awk \ @@ -1254,7 +1260,7 @@ GAWK_EXT_TESTS = \ colonwarn clos1way dbugeval delsub devfd devfd1 devfd2 dumpvars exit \ fieldwdth fpat1 fpat2 fpat3 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ - gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ + genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ include include2 indirectcall indirectcall2 \ @@ -1262,7 +1268,7 @@ GAWK_EXT_TESTS = \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ patsplit posix printfbad1 printfbad2 printfbad3 printhuge procinfs \ - profile1 profile2 profile3 profile4 profile5 pty1 \ + profile1 profile2 profile3 profile4 profile5 profile6 profile7 pty1 \ rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \ rsstart2 rsstart3 rstest6 shadow sortfor sortu split_after_fpat \ splitarg4 strftime \ @@ -1593,6 +1599,8 @@ charset-msg-start: @echo "************************************************" @echo "** Some or all of these tests may fail if you **" @echo "** have inadequate or missing locale support **" + @echo "** At least en_US.UTF-8, ru_RU.UTF-8 and **" + @echo "** ja_JP.UTF-8 are needed. **" @echo "************************************************" charset-msg-end: @@ -2094,7 +2102,7 @@ profile1: @echo $@ @$(AWK) -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1 @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk - @$(AWK) -f ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out + @$(AWK) -f ./ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out @$(CMP) _$@.out1 _$@.out2 && rm _$@.out[12] || { echo EXIT CODE: $$? >>_$@ ; \ cp "$(srcdir)"/dtdgport.awk $@.ok ; } @@ -2112,13 +2120,23 @@ profile3: profile4: @echo $@ - @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null - @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out + @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ profile5: @echo $@ - @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null + @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +profile6: + @echo $@ + @$(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null + @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +profile7: + @echo $@ + @$(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @@ -2284,7 +2302,7 @@ inplace3:: testext:: @echo $@ @$(AWK) '/^(@load|BEGIN)/,/^}/' "$(top_srcdir)"/extension/testext.c > testext.awk - @$(AWK) -f testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk readdir: @@ -2399,6 +2417,11 @@ filefuncs: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk -v builddir="$(abs_top_builddir)" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +genpot: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --gen-pot >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ Gt-dummy: # file Maketests, generated from Makefile.am by the Gentests program addcomma: diff --git a/test/genpot.awk b/test/genpot.awk new file mode 100644 index 00000000..990b0b5c --- /dev/null +++ b/test/genpot.awk @@ -0,0 +1 @@ +{print _"This string is so long that gawk --gen-pot will break it and lose a letter at the break."} diff --git a/test/genpot.ok b/test/genpot.ok new file mode 100644 index 00000000..35c0cc99 --- /dev/null +++ b/test/genpot.ok @@ -0,0 +1,5 @@ +#: genpot.awk:1 +msgid "This string is so long that gawk --gen-pot will break it and lose a l" +"etter at the break." +msgstr "" + diff --git a/test/profile2.ok b/test/profile2.ok index 50c7e190..938d6858 100644 --- a/test/profile2.ok +++ b/test/profile2.ok @@ -1,4 +1,4 @@ - # BEGIN block(s) + # BEGIN rule(s) BEGIN { 1 if (sortcmd == "") { diff --git a/test/profile3.ok b/test/profile3.ok index 50172c48..bbf06541 100644 --- a/test/profile3.ok +++ b/test/profile3.ok @@ -1,4 +1,4 @@ - # BEGIN block(s) + # BEGIN rule(s) BEGIN { 1 the_func = "p" diff --git a/test/profile4.ok b/test/profile4.ok index 8ff4470f..9d2b9430 100644 --- a/test/profile4.ok +++ b/test/profile4.ok @@ -1,11 +1,9 @@ - # BEGIN block(s) - - BEGIN { - a = "foo" (c = "bar") - a = (b - c) "foo" - a = "foo" (b - c) - q = (d = "x") (e = "y") - a = (c = tolower("FOO")) in JUNK - x = y == 0 && z == 2 && q == 45 - } +BEGIN { + a = "foo" (c = "bar") + a = (b - c) "foo" + a = "foo" (b - c) + q = (d = "x") (e = "y") + a = (c = tolower("FOO")) in JUNK + x = y == 0 && z == 2 && q == 45 +} diff --git a/test/profile5.ok b/test/profile5.ok index cc83dc06..4c944627 100644 --- a/test/profile5.ok +++ b/test/profile5.ok @@ -1,4770 +1,5728 @@ - # BEGIN block(s) +BEGIN { + _addlib("_BASE") +} + +############################################################################ + +BEGIN { + BINMODE = "rw" + SUBSEP = "\000" + _NULARR[""] + delete _NULARR[""] + _INITBASE() +} + +BEGIN { + _addlib("_sYS") +} + +BEGIN { + _addlib("_rEG") +} + +BEGIN { + _addlib("_INSTRUC") +} + +############################################################################# + +BEGIN { + _delay_perfmsdelay = 11500 +} + +BEGIN { + _addlib("_ARR") +} + +#___________________________________________________________________________________ +BEGIN { +} + +########################################################################### + + + + + + +BEGIN { + _addlib("_EXTFN") +} + +############################################################################# + +BEGIN { + delete _XCHR + delete _ASC + delete _CHR + t = "" + for (i = 0; i < 256; i++) { + _ASC[a = _CHR[i] = sprintf("%c", i)] = i + _QASC[a] = sprintf("%.3o", i) + _XCHR[_CHR[i]] = sprintf("%c", (i < 128 ? i + 128 : i - 128)) + } + #_____________________________________________________________________________ + + for (i = 0; i < 256; i++) { + _QSTRQ[_CHR[i]] = "\\" sprintf("%.3o", i) + } + #_______________________________________________________________________ + + for (i = 0; i < 32; i++) { + _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + for (; i < 128; i++) { + _QSTR[_CHR[i]] = _CHR[i] + } + for (; i < 256; i++) { + _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + _QSTR["\\"] = "\\\\" + #; _QSTR["\""]="\\\"" + #_____________________________________________________________________________ + + _CHR["CR"] = "\r" + _CHR["EOL"] = "\r\n" + _CHR["EOF"] = "\032" + _QSTR[_CHR["EOL"]] = "\\015\\012" + #_______________________________________________________________________ + + _CHR["MONTH"][_CHR["MONTH"]["Jan"] = "01"] = "Jan" + _CHR["MONTH"][_CHR["MONTH"]["Feb"] = "02"] = "Feb" + _CHR["MONTH"][_CHR["MONTH"]["Mar"] = "03"] = "Mar" + _CHR["MONTH"][_CHR["MONTH"]["Apr"] = "04"] = "Apr" + _CHR["MONTH"][_CHR["MONTH"]["May"] = "05"] = "May" + _CHR["MONTH"][_CHR["MONTH"]["Jun"] = "06"] = "Jun" + _CHR["MONTH"][_CHR["MONTH"]["Jul"] = "07"] = "Jul" + _CHR["MONTH"][_CHR["MONTH"]["Aug"] = "08"] = "Aug" + _CHR["MONTH"][_CHR["MONTH"]["Sep"] = "09"] = "Sep" + _CHR["MONTH"][_CHR["MONTH"]["Oct"] = "10"] = "Oct" + _CHR["MONTH"][_CHR["MONTH"]["Nov"] = "11"] = "Nov" + _CHR["MONTH"][_CHR["MONTH"]["Dec"] = "12"] = "Dec" + #_____________________________________________________________________________ + + _TAB_STEP_DEFAULT = 8 + #_____________________________________________________________________________ + + for (i = 0; i < 32; i++) { + _REXPSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + for (; i < 256; i++) { + _REXPSTR[_CHR[i]] = _CHR[i] + } + _gensubfn("\\^$.()|{,}[-]?+*", ".", "_rexpstr_i0") +} + +BEGIN { + _addlib("_SYSIO") +} + +############################################################################# + +BEGIN { + _SYS_STDCON = "CON" + _CON_WIDTH = (match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80) +} + +BEGIN { + _addlib("_FILEIO") +} + +############################################################################# + +BEGIN { + if (_SYS_STDOUT == "") { + _SYS_STDOUT = "/dev/stdout" + } + if (_SYS_STDERR == "") { + _SYS_STDERR = "/dev/stderr" + } + _CHR["SUBDIR"] = "\\" + if (_gawk_scriptlevel < 1) { + match(b = _cmd("echo %CD% 2>NUL"), /[^\x00-\x1F]*/) + ENVIRON["CD"] = _FILEIO_RD = _filerd(substr(b, RSTART, RLENGTH) _CHR["SUBDIR"]) + _FILEIO_R = _filer(_FILEIO_RD) + _FILEIO_D = _filed(_FILEIO_RD) + _setmpath(_filerd(_FILEIO_RD "_tmp" _CHR["SUBDIR"])) + } +} + +BEGIN { + _addlib("_tOBJ") +} + +############################################################################# +BEGIN { + _tInBy = "\212._tInBy" + _tgenuid_init() + _UIDS[""] + delete _UIDS[""] + _UIDSDEL[""] + delete _UIDSDEL[""] + _tPREV[""] + _tPARENT[""] + _tNEXT[""] + _tFCHLD[""] + _tQCHLD[""] + _tLCHLD[""] + _tLINK[""] + _tCLASS[""] + _tSTR[""] + _tDLINK[""] + _[""] + delete _[""] + _ptr[""] + delete _ptr[""] + _TMP0[""] + delete _TMP0[""] + _TMP1[""] + delete _TMP1[""] +} + +BEGIN { + _addlib("_ERRLOG") +} + +############################################################################# + +BEGIN { + if (_gawk_scriptlevel < 1) { + _ERRLOG_TF = 1 + _ERRLOG_VF = 1 + _ERRLOG_IF = 1 + _ERRLOG_WF = 1 + _ERRLOG_EF = 1 + _ERRLOG_FF = 1 + _wrfile(_errlog_file = _getmpfile("OUTPUT.LOG"), "") + } +} + +BEGIN { + _addlib("_SHORTCUT") +} + +#___________________________________________________________________________________ +BEGIN { + _shortcut_init() +} + +######################################################### + + + +BEGIN { + _addlib("_eXTFN") +} + +#___________________________________________________________________________________ +BEGIN { + _extfn_init() +} + +############################################################ + + +BEGIN { + _addlib("_sHARE") +} + +BEGIN { + _addlib("_FILEVER") +} + +BEGIN { + _addlib("_DS") + ############################################################################### + + _PRODUCT_NAME = "Deployment Solution Control" + _PRODUCT_VERSION = "1.0" + _PRODUCT_COPYRIGHT = "Copyright (C) 2013 by CosumoGEN" + _PRODUCT_FILENAME = "_main.ewk" +} + +# problem configuring uid by array charset: i can' understand what format of the array: possibly - remove array support +# after removal of array format detection: there is unfinished conflicts: it is possible to totally remove array uid-gen initialization + +#_____________________________________________________ +BEGIN { + _inituidefault() +} + +#_____________________________________________________ +BEGIN { + _initfilever() +} + +#_____________________________________________________ +BEGIN { + _initshare() +} + +#_________________________________________________________________ +BEGIN { + _inspass(_IMPORT, "_import_data") +} + +#_______________________________________________ +BEGIN { + _TEND[_ARRLEN] = 0 + _TYPEWORD = "_TYPE" +} + +#_______________________________________________ +BEGIN { + _ARRLEN = "\032LEN" + _ARRPTR = "\032PTR" + _ARRSTR = "" +} + +#_____________________________________________________ +BEGIN { + _getperf_fn = "_nop" +} + +BEGIN { + _datablock_length = 262144 +} + +#_____________________________________________________ +BEGIN { + _initrdreg() +} + +#_____________________________________________________ +BEGIN { + _initregpath0() +} - BEGIN { - _addlib("_BASE") - } +#_____________________________________________________ +BEGIN { + _initsys() +} - BEGIN { - BINMODE = "rw" - SUBSEP = "\000" - _NULARR[""] - delete _NULARR[""] - _INITBASE() - } - - BEGIN { - _addlib("_sYS") +############################################################################ + +BEGIN { + a = ENVIRON["EGAWK_CMDLINE"] + gsub(/^[ \t]*/, "", a) + a = _lib_CMDLN(a) + if (a != "" && ! _LIBAPI["F"]["!"]) { + _out(_lib_HELP()) + _fatal("Bad comandline argument `" a "'") + } + gsub(/^[ \t]*/, "", a) + ENVIRON["EGAWK_CMDLINE"] = a + _lib_APPLY() + if (_basexit_fl) { + exit + } + _INIT() + _START() + _END() +} + +######################################################################## + +END { + _EXIT() +} + +############################################################################### + +END { + if (_gawk_scriptlevel < 1) { + close(_errlog_file) + p = _Zimport(_rdfile(_errlog_file), _N()) + if ((t = _get_errout(p)) != "") { + _expout(t, "/dev/stderr") + } + } +} + +############################################################################### + +END { + if (_gawk_scriptlevel < 1) { + if (! _fileio_notdeltmpflag) { + _FILEIO_TMPATHS[_FILEIO_TMPRD] + _Foreach(_FILEIO_TMPATHS, "_uninit_del") + } + } +} + +############################################################################### +END { + if (_constatstrln > 0) { + _constat() } +} - BEGIN { - _addlib("_rEG") - } +#___________________________________________________________________________________ +#################################################################################### - BEGIN { - _addlib("_INSTRUC") - } - BEGIN { - _delay_perfmsdelay = 11500 - } - BEGIN { - _addlib("_ARR") - } - BEGIN { - } - BEGIN { - _addlib("_EXTFN") - } - BEGIN { - delete _XCHR - delete _ASC - delete _CHR - t = "" - for (i = 0; i < 256; i++) { - _ASC[a = _CHR[i] = sprintf("%c", i)] = i - _QASC[a] = sprintf("%.3o", i) - _XCHR[_CHR[i]] = sprintf("%c", (i < 128 ? i + 128 : i - 128)) - } - for (i = 0; i < 256; i++) { - _QSTRQ[_CHR[i]] = "\\" sprintf("%.3o", i) - } - for (i = 0; i < 32; i++) { - _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - for (; i < 128; i++) { - _QSTR[_CHR[i]] = _CHR[i] - } - for (; i < 256; i++) { - _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - _QSTR["\\"] = "\\\\" - _CHR["CR"] = "\r" - _CHR["EOL"] = "\r\n" - _CHR["EOF"] = "\032" - _QSTR[_CHR["EOL"]] = "\\015\\012" - _CHR["MONTH"][_CHR["MONTH"]["Jan"] = "01"] = "Jan" - _CHR["MONTH"][_CHR["MONTH"]["Feb"] = "02"] = "Feb" - _CHR["MONTH"][_CHR["MONTH"]["Mar"] = "03"] = "Mar" - _CHR["MONTH"][_CHR["MONTH"]["Apr"] = "04"] = "Apr" - _CHR["MONTH"][_CHR["MONTH"]["May"] = "05"] = "May" - _CHR["MONTH"][_CHR["MONTH"]["Jun"] = "06"] = "Jun" - _CHR["MONTH"][_CHR["MONTH"]["Jul"] = "07"] = "Jul" - _CHR["MONTH"][_CHR["MONTH"]["Aug"] = "08"] = "Aug" - _CHR["MONTH"][_CHR["MONTH"]["Sep"] = "09"] = "Sep" - _CHR["MONTH"][_CHR["MONTH"]["Oct"] = "10"] = "Oct" - _CHR["MONTH"][_CHR["MONTH"]["Nov"] = "11"] = "Nov" - _CHR["MONTH"][_CHR["MONTH"]["Dec"] = "12"] = "Dec" - _TAB_STEP_DEFAULT = 8 - for (i = 0; i < 32; i++) { - _REXPSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - for (; i < 256; i++) { - _REXPSTR[_CHR[i]] = _CHR[i] - } - _gensubfn("\\^$.()|{,}[-]?+*", ".", "_rexpstr_i0") - } - BEGIN { - _addlib("_SYSIO") - } +# make sure that stdout contain only expected characters +# make sure that stderr contain only expected characters +# redesign & reformat keys and its outputs +# try different key combinations +# add lib-specified to all libs - BEGIN { - _SYS_STDCON = "CON" - _CON_WIDTH = (match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80) - } - BEGIN { - _addlib("_FILEIO") - } - - BEGIN { - if (_SYS_STDOUT == "") { - _SYS_STDOUT = "/dev/stdout" - } - if (_SYS_STDERR == "") { - _SYS_STDERR = "/dev/stderr" - } - _CHR["SUBDIR"] = "\\" - if (_gawk_scriptlevel < 1) { - match(b = _cmd("echo %CD% 2>NUL"), /[^\x00-\x1F]*/) - ENVIRON["CD"] = _FILEIO_RD = _filerd(substr(b, RSTART, RLENGTH) _CHR["SUBDIR"]) - _FILEIO_R = _filer(_FILEIO_RD) - _FILEIO_D = _filed(_FILEIO_RD) - _setmpath(_filerd(_FILEIO_RD "_tmp" _CHR["SUBDIR"])) +#_______________________________________________________________________ +function W(p, p0, p1) +{ + ##################################################### + if (isarray(p0)) { + delete p0[p] + if (isarray(p1)) { + for (i in p1) { + if (isarray(p1[i])) { + p0[p][i][""] + delete p0[p][i][""] + _N_i0(p0[p][i], p1[i]) + } else { + p0[p][i] = p1[i] + } + } + return p } + return (p0[p] = p1) } - - BEGIN { - _addlib("_tOBJ") - } - - BEGIN { - _tInBy = "\212._tInBy" - _tgenuid_init() - _UIDS[""] - delete _UIDS[""] - _UIDSDEL[""] - delete _UIDSDEL[""] - _tPREV[""] - _tPARENT[""] - _tNEXT[""] - _tFCHLD[""] - _tQCHLD[""] - _tLCHLD[""] - _tLINK[""] - _tCLASS[""] - _tSTR[""] - _tDLINK[""] - _[""] - delete _[""] - _ptr[""] - delete _ptr[""] - _TMP0[""] - delete _TMP0[""] - _TMP1[""] - delete _TMP1[""] - } - - BEGIN { - _addlib("_ERRLOG") - } - - BEGIN { - if (_gawk_scriptlevel < 1) { - _ERRLOG_TF = 1 - _ERRLOG_VF = 1 - _ERRLOG_IF = 1 - _ERRLOG_WF = 1 - _ERRLOG_EF = 1 - _ERRLOG_FF = 1 - _wrfile(_errlog_file = _getmpfile("OUTPUT.LOG"), "") + delete _[p][p0] + if (isarray(p1)) { + for (i in p1) { + if (isarray(p1[i])) { + _[p][p0][i][""] + delete _[p][p0][i][""] + _N_i0(_[p][p0][i], p1[i]) + } else { + _[p][p0][i] = p1[i] + } } + return p } + return (_[p][p0] = p1) +} - BEGIN { - _addlib("_SHORTCUT") - } - - BEGIN { - _shortcut_init() - } - - BEGIN { - _addlib("_eXTFN") - } - - BEGIN { - _extfn_init() - } - - BEGIN { - _addlib("_sHARE") - } - - BEGIN { - _addlib("_FILEVER") - } - - BEGIN { - _addlib("_DS") - _PRODUCT_NAME = "Deployment Solution Control" - _PRODUCT_VERSION = "1.0" - _PRODUCT_COPYRIGHT = "Copyright (C) 2013 by CosumoGEN" - _PRODUCT_FILENAME = "_main.ewk" - } - - BEGIN { - _inituidefault() - } - - BEGIN { - _initfilever() - } - - BEGIN { - _initshare() - } - - BEGIN { - _inspass(_IMPORT, "_import_data") - } - - BEGIN { - _TEND[_ARRLEN] = 0 - _TYPEWORD = "_TYPE" - } - - BEGIN { - _ARRLEN = "\032LEN" - _ARRPTR = "\032PTR" - _ARRSTR = "" - } - - BEGIN { - _getperf_fn = "_nop" - } - - BEGIN { - _datablock_length = 262144 - } - - BEGIN { - _initrdreg() - } - - BEGIN { - _initregpath0() - } - - BEGIN { - _initsys() - } +########################################################## - BEGIN { - a = ENVIRON["EGAWK_CMDLINE"] - gsub(/^[ \t]*/, "", a) - a = _lib_CMDLN(a) - if (a != "" && ! _LIBAPI["F"]["!"]) { - _out(_lib_HELP()) - _fatal("Bad comandline argument `" a "'") - } - gsub(/^[ \t]*/, "", a) - ENVIRON["EGAWK_CMDLINE"] = a - _lib_APPLY() - if (_basexit_fl) { - exit - } - _INIT() - _START() - _END() +function _ARR(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_ARR 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - # END block(s) +########################################################## - END { - _EXIT() - } - - END { - if (_gawk_scriptlevel < 1) { - close(_errlog_file) - p = _Zimport(_rdfile(_errlog_file), _N()) - if ((t = _get_errout(p)) != "") { - _expout(t, "/dev/stderr") +function _BASE(c, t, P, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^((--([Vv])ersion)|(-([Vv])))[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + _cmdln_version = A[3] A[5] + } else { + if (match(t, /^((-?\?)|(--help))[ \t]*/)) { + t = substr(t, RLENGTH + 1) + _cmdln_help = 1 + } else { + if (match(t, /^--[ \t]*/)) { + return _endpass(substr(t, RLENGTH + 1)) + } } } - } - - END { - if (_gawk_scriptlevel < 1) { - if (! _fileio_notdeltmpflag) { - _FILEIO_TMPATHS[_FILEIO_TMPRD] - _Foreach(_FILEIO_TMPATHS, "_uninit_del") - } + return t + #___________________________________________________________ + + case "_lib_APPLY": + if (_cmdln_help) { + match(_fbaccr(_LIBAPI, "_lib_HELP"), /^([^\x00]*)\x00([^\x01]*)\x01(.*)/, A) + _out(A[2] A[1] A[3]) + return _endpass(_basexit_fl = 1) + } + if (_cmdln_version) { + _out(_ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() ((_cmdln_version == "v" ? "" : _lib_NAMEVER()))) + return _endpass(_basexit_fl = 1) } + return + #___________________________________________________________ + + case "_lib_HELP": + return ("\000" _ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() _ln(" Usage:") _ln() _ln(" " _PRODUCT_FILENAME " [/key1 /key2...] [-- cmdline]") _ln() _ln(" keys:") _ln() "\001" _ln(" -v -V --version - output product version and (if /V) all modules") _ln(" ? -? --help - output this help page") _ln(" -- - command line string edge")) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_BASE 3.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - END { - if (_constatstrln > 0) { - _constat() - } +#____________________________________________________________________________ +function _DS(c, t, P, a, A) +{ + ###################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return (_ln() _ln(" Usage: " _PRODUCT_NAME " [/key1 /key2...] sourcefile [cmdline]") _ln()) + #_____________________________________________________ + case "_lib_NAMEVER": + return + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} +#______________________________________________________________________________________________ +function _END() +{ + ################################################################################# + +} - # Functions, listed alphabetically +######################################################## - function W(p, p0, p1) - { - if (isarray(p0)) { - delete p0[p] - if (isarray(p1)) { - for (i in p1) { - if (isarray(p1[i])) { - p0[p][i][""] - delete p0[p][i][""] - _N_i0(p0[p][i], p1[i]) - } else { - p0[p][i] = p1[i] - } - } - return p - } - return (p0[p] = p1) +function _ERRLOG(c, t, P, a, b, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^[ \t]*-L:([TtVvIiWwEeFf]*)[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + _errlog_errflkey = _errlog_errflkey A[1] } - delete _[p][p0] - if (isarray(p1)) { - for (i in p1) { - if (isarray(p1[i])) { - _[p][p0][i][""] - delete _[p][p0][i][""] - _N_i0(_[p][p0][i], p1[i]) + return t + #_______________________________________________________________________ + + case "_lib_APPLY": + if (_errlog_errflkey) { + split(_errlog_errflkey, A, "") + for (a = 1; a in A; a++) { + if (A[a] == toupper(A[a])) { + b = 1 } else { - _[p][p0][i] = p1[i] + b = "" + } + switch (toupper(A[a])) { + case "T": + _ERRLOG_TF = b + break + case "V": + _ERRLOG_VF = b + break + case "I": + _ERRLOG_IF = b + break + case "W": + _ERRLOG_WF = b + break + case "E": + _ERRLOG_EF = b + break + case "F": + _ERRLOG_FF = b + break } } - return p + if (_ERRLOG_IF) { + _info("Log-message types inherited acc/deny: " "TRACE " ((_ERRLOG_TF ? "ON" : "OFF")) "/" "VERBOSE " ((_ERRLOG_VF ? "ON" : "OFF")) "/" "INFO " ((_ERRLOG_IF ? "ON" : "OFF")) "/" "WARNING " ((_ERRLOG_WF ? "ON" : "OFF")) "/" "ERROR " ((_ERRLOG_EF ? "ON" : "OFF")) "/" "FATAL " ((_ERRLOG_FF ? "ON" : "OFF"))) + } } - return (_[p][p0] = p1) + return + #_______________________________________________________________________ + + case "_lib_HELP": + return (_ln(" -L:TtVvIiWwEeFf - enable(upcase: TVIWEF) or disable(lowcase: tviwef) allowable type of") _ln(" log messages. Trace/Verbose/Informational/Warning/Error/Fatal.") _ln()) + #_______________________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_ERRLOG 1.0") + #_______________________________________________________________________ + + case "_lib_BEGIN": + P["_ERRLOG_TF"] = _ERRLOG_TF + P["_ERRLOG_VF"] = _ERRLOG_VF + P["_ERRLOG_IF"] = _ERRLOG_IF + P["_ERRLOG_WF"] = _ERRLOG_WF + P["_ERRLOG_EF"] = _ERRLOG_EF + P["_ERRLOG_FF"] = _ERRLOG_FF + P["_errlog_file"] = "/dev/stderr" + return } +} - function _ARR(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_ARR 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - } +#______________________________________________________________________________________________ +function _EXIT() +{ + ################################################################################ + +} + +######################################################## + +function _EXTFN(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_EXTFN 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _BASE(c, t, P, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^((--([Vv])ersion)|(-([Vv])))[ \t]*/, A)) { - t = substr(t, RLENGTH + 1) - _cmdln_version = A[3] A[5] +####################################################### + +function _FILEIO(c, t, P, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^[ \t]*-[Tt]([\+-])[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + if (A[1] == "+") { + _fileio_notdeltmpflag = 1 } else { - if (match(t, /^((-?\?)|(--help))[ \t]*/)) { - t = substr(t, RLENGTH + 1) - _cmdln_help = 1 - } else { - if (match(t, /^--[ \t]*/)) { - return _endpass(substr(t, RLENGTH + 1)) - } - } - } - return t - case "_lib_APPLY": - if (_cmdln_help) { - match(_fbaccr(_LIBAPI, "_lib_HELP"), /^([^\x00]*)\x00([^\x01]*)\x01(.*)/, A) - _out(A[2] A[1] A[3]) - return _endpass(_basexit_fl = 1) + _fileio_notdeltmpflag = "" } - if (_cmdln_version) { - _out(_ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() ((_cmdln_version == "v" ? "" : _lib_NAMEVER()))) - return _endpass(_basexit_fl = 1) - } - return - case "_lib_HELP": - return ("\000" _ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() _ln(" Usage:") _ln() _ln(" " _PRODUCT_FILENAME " [/key1 /key2...] [-- cmdline]") _ln() _ln(" keys:") _ln() "\001" _ln(" -v -V --version - output product version and (if /V) all modules") _ln(" ? -? --help - output this help page") _ln(" -- - command line string edge")) - case "_lib_NAMEVER": - return _ln("_BASE 3.0") - case "_lib_BEGIN": - return - case "_lib_END": - return } - } - - function _DS(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return (_ln() _ln(" Usage: " _PRODUCT_NAME " [/key1 /key2...] sourcefile [cmdline]") _ln()) - case "_lib_NAMEVER": - return - case "_lib_BEGIN": - return - case "_lib_END": - return + return t + #___________________________________________________________ + + case "_lib_APPLY": + if (_fileio_notdeltmpflag) { + _info("Temporary objects deletion DISABLED (inherited)") + } + return + #___________________________________________________________ + + case "_lib_HELP": + return (_ln(" -[Tt][+-] - inherited: +enable\\-disable temporary files\\dirs deletion") _ln()) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_FILEIO 2.1") + #___________________________________________________________ + + case "_lib_BEGIN": + P["ENVIRON"]["CD"] = ENVIRON["CD"] + P["_FILEIO_RD"] = _FILEIO_RD + P["_FILEIO_R"] = _FILEIO_R + P["_FILEIO_D"] = _FILEIO_D + if (! ("_FILEIO_TMPRD" in P)) { + P["_FILEIO_TMPRD"] = _getmpdir(_filen(P["SOURCE"]) "." ++_egawk_subcntr _CHR["SUBDIR"]) } + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _END() - { +############################################################ +#_____________________________________________________________________________ +function _FILEVER(c, t, P, a, A) +{ + ################################################# + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _ERRLOG(c, t, P, a, b, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^[ \t]*-L:([TtVvIiWwEeFf]*)[ \t]*/, A)) { - t = substr(t, RLENGTH + 1) - _errlog_errflkey = _errlog_errflkey A[1] - } - return t - case "_lib_APPLY": - if (_errlog_errflkey) { - split(_errlog_errflkey, A, "") - for (a = 1; a in A; a++) { - if (A[a] == toupper(A[a])) { - b = 1 - } else { - b = "" - } - switch (toupper(A[a])) { - case "T": - _ERRLOG_TF = b - break - case "V": - _ERRLOG_VF = b - break - case "I": - _ERRLOG_IF = b - break - case "W": - _ERRLOG_WF = b - break - case "E": - _ERRLOG_EF = b - break - case "F": - _ERRLOG_FF = b - break - } - } - if (_ERRLOG_IF) { - _info("Log-message types inherited acc/deny: " "TRACE " ((_ERRLOG_TF ? "ON" : "OFF")) "/" "VERBOSE " ((_ERRLOG_VF ? "ON" : "OFF")) "/" "INFO " ((_ERRLOG_IF ? "ON" : "OFF")) "/" "WARNING " ((_ERRLOG_WF ? "ON" : "OFF")) "/" "ERROR " ((_ERRLOG_EF ? "ON" : "OFF")) "/" "FATAL " ((_ERRLOG_FF ? "ON" : "OFF"))) - } - } - return - case "_lib_HELP": - return (_ln(" -L:TtVvIiWwEeFf - enable(upcase: TVIWEF) or disable(lowcase: tviwef) allowable type of") _ln(" log messages. Trace/Verbose/Informational/Warning/Error/Fatal.") _ln()) - case "_lib_NAMEVER": - return _ln("_ERRLOG 1.0") - case "_lib_BEGIN": - P["_ERRLOG_TF"] = _ERRLOG_TF - P["_ERRLOG_VF"] = _ERRLOG_VF - P["_ERRLOG_IF"] = _ERRLOG_IF - P["_ERRLOG_WF"] = _ERRLOG_WF - P["_ERRLOG_EF"] = _ERRLOG_EF - P["_ERRLOG_FF"] = _ERRLOG_FF - P["_errlog_file"] = "/dev/stderr" - return - } +function _Foreach(A, f, p0, i) +{ + for (i in A) { + @f(A, i, p0) } +} - function _EXIT() - { - } +function _INIT(f) +{ +} - function _EXTFN(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_EXTFN 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } +#___________________________________________________________________________________ +function _INITBASE() +{ + ################################################################ + + _egawk_utilpath = ENVIRON["EGAWK_PATH"] "BIN\\UTIL\\" +} - function _FILEIO(c, t, P, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^[ \t]*-[Tt]([\+-])[ \t]*/, A)) { - t = substr(t, RLENGTH + 1) - if (A[1] == "+") { - _fileio_notdeltmpflag = 1 - } else { - _fileio_notdeltmpflag = "" - } - } - return t - case "_lib_APPLY": - if (_fileio_notdeltmpflag) { - _info("Temporary objects deletion DISABLED (inherited)") - } - return - case "_lib_HELP": - return (_ln(" -[Tt][+-] - inherited: +enable\\-disable temporary files\\dirs deletion") _ln()) - case "_lib_NAMEVER": - return _ln("_FILEIO 2.1") - case "_lib_BEGIN": - P["ENVIRON"]["CD"] = ENVIRON["CD"] - P["_FILEIO_RD"] = _FILEIO_RD - P["_FILEIO_R"] = _FILEIO_R - P["_FILEIO_D"] = _FILEIO_D - if (! ("_FILEIO_TMPRD" in P)) { - P["_FILEIO_TMPRD"] = _getmpdir(_filen(P["SOURCE"]) "." ++_egawk_subcntr _CHR["SUBDIR"]) - } - return - case "_lib_END": - return - } - } +###################################################### - function _FILEVER(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return - case "_lib_BEGIN": - return - case "_lib_END": - return - } +function _INSTRUC(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_INSTRUC 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _Foreach(A, f, p0, i) - { - for (i in A) { - @f(A, i, p0) - } - } +#___________________________________________________________________________________ - function _INIT(f) - { - } - function _INITBASE() - { - _egawk_utilpath = ENVIRON["EGAWK_PATH"] "BIN\\UTIL\\" - } +#################################################################################### - function _INSTRUC(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_INSTRUC 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } - function _N(F, v, p) - { - for (p in _UIDS) { - delete _UIDS[p] - return _nN_i0(p, F, v) - } - return _nN_i0(_tgenuid(), F, v) +#_____________________________________________________________________________ +function _N(F, v, p) +{ + ########################################################### + for (p in _UIDS) { + delete _UIDS[p] + return _nN_i0(p, F, v) } + return _nN_i0(_tgenuid(), F, v) +} - function _SHORTCUT(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_shortcut 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } +##################################################### - function _START(t, i, A) - { - _torexp_init() - test_uid() +function _SHORTCUT(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": return - _conl(patsplit("a,b,c", A, /[^,]/, B)) - test_splitstr() + #___________________________________________________________ + + case "_lib_HELP": return - A[""] - _CLASSPTR["ptr"] - ALTARR["ptra"] - _conl(_dumparr(SYMTAB)) - BB[1] = _NOP - zorr(1, 2, 3, 4, 5, 6) - zorr(BB, 1) - _rtn() - _rtn("") - _rtn(0) - _rtn("0") - _rtn(1) - _rtn("1") - _rtn(-1) - _rtn("-1") - _rtn("huj") - _rtn("ptr") - _rtn("ptra", ALTARR) - _rtn(ALTARR) - _rtn(ALTARR, ALTARR) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_shortcut 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": return - _tstini() + #___________________________________________________________ + + case "_lib_END": return - _splitpath_test() + } +} + +#______________________________________________________________________________________________ +function _START(t, i, A) +{ + ######################################################################### + _torexp_init() + test_uid() + return + _conl(patsplit("a,b,c", A, /[^,]/, B)) + test_splitstr() + return + A[""] + _CLASSPTR["ptr"] + ALTARR["ptra"] + _conl(_dumparr(SYMTAB)) + BB[1] = _NOP + zorr(1, 2, 3, 4, 5, 6) + zorr(BB, 1) + _rtn() + _rtn("") + _rtn(0) + _rtn("0") + _rtn(1) + _rtn("1") + _rtn(-1) + _rtn("-1") + _rtn("huj") + _rtn("ptr") + _rtn("ptra", ALTARR) + _rtn(ALTARR) + _rtn(ALTARR, ALTARR) + return + _tstini() + return + _splitpath_test() + # _split_regpath() + return + hh = "CPU" + _conl("go1!") + _conl(_var(_sharepath(hh, "gdfsgdsgsd sdgsdighjui teretiewrotrewut 345345345 rtjtireutireu huj"))) + _conl("go2!") + _conl(_var(_sharelist(AAA, hh), _dumparr(AAA))) + _conline() + A[1] = "h" + A[3] = "j" + t = "pizda" + if (match(t, /^pi(Z)da/, A)) { + _conl("match") + } else { + _conl("not match") + } + _conl(_dumparr(A)) + return + _pathSMA = "C:\\Program Files\\Altiris\\Altiris Agent\\" + DSPlugInPath = _pathSMA "Agents\\Deployment\\Agent\\" + DSAutoPath = _pathSMA + if (! _sysinfo(_SYS, _hostname)) { + _fatal("_sysinfo: unknown error") + } + _REG[""] + delete _REG[""] + _servoutput = _CHR["EOL"] _cmd("sc query state= all") + _dsbasepath = "\\\\CPU\\CPU\\DEV\\PROJECT\\_DS\\" + _rdreg(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris") + _wrfile("rego.txt", _dumparr(_REG)) + _conl("fF") + #_______________________________________________________________________ + + c = _getreg_i1(DDD, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\\204~.*\224Install path", _REG) + #_________________________________________________________________________________________ + pp = _n("NAME", "NS") + #pp=_n() + #___________________________________________________________________________________ + p = _defsolution(pp, "DS Plug-in", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") + ClientConfiguration = _defdll(p, "Client Configuration", "ClientConfiguration") + ClientImagingPrep = _defdll(p, "Client Inaging Preparation", "ClientImagingPrep") + ClientImaging = _defdll(p, "Client Imaging", "ClientImaging") + ClientPCT = _defdll(p, "Client PCT", "ClientPCT") + ClientRebootTo = _defdll(p, "Client Reboot To", "ClientRebootTo") + DeploymentAgent = _defdll(p, "Deployment Agent", "Deployment Agent") + DeploymentSolutionBaseAgent = _defdll(p, "Deployment Solution Base Agent", "Deployment Solution Base Agent") + ClientBCDEdit = _defile(p, "Client BCD Edit", "ClientBCDEdit.dll") + ClientCopyFile = _defile(p, "Client Copy File", "ClientCopyFile.dll") + ClientPreImage = _defile(p, "Client Pre Image", "ClientPreImage.dll") + ClientRebootTo = _defile(p, "Client Reboot To", "ClientRebootTo.dll") + _defile(p, "ConfigService.exe", "ConfigService.exe", "") + _defile(p, "config.dll", "config.dll", "") + _defsrv(p, "DS Plug-in Service", "Altiris Deployment Solution - System Configuration") + _defreg(p, "Deployment Agent Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR") + _defile(p, "Altiris_DeploymentSolutionAgent_7_1_x86.msi", (_SYS["OSArchitecture"] == "64-bit" ? "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{9D76E4CA-377A-472D-A82E-EDAD77E7E4ED}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x64.msi" : "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{4B747D25-612F-48FC-B6B5-9916D1BB755C}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x86.msi"), "") + _defdir(p, "Deployment Folder", a = gensub(/[^\\]*$/, "", 1, _rdsafe(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR", "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\Deployment\\Agent\\"))) + #___________________________________________________________________________________ + p = _defsolution(pp, "DS Auto", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") + _defdir(p, "C:\\Boot\\Altiris\\iso\\boot\\fonts\\", "C:\\Boot\\Altiris\\iso\\boot\\fonts\\") + _defdir(p, "C:\\Boot\\Altiris\\iso\\sources\\", "C:\\Boot\\Altiris\\iso\\sources\\") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.exe", "C:\\Boot\\Altiris\\iso\\autoinst.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.ini", "C:\\Boot\\Altiris\\iso\\autoinst.ini", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.exe", "C:\\Boot\\Altiris\\iso\\autoutil.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.ini", "C:\\Boot\\Altiris\\iso\\autoutil.ini", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bootmgr", "C:\\Boot\\Altiris\\iso\\bootmgr", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bootsect.exe", "C:\\Boot\\Altiris\\iso\\bootsect.exe", "") + _defreg(p, "Deployment Automation reg.File", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\File.XSZ", "autoutil.exe") + _defreg(p, "Deployment Automation reg.Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\Path.XSZ", "%systemdrive%\\boot\\altiris\\iso") + #_________________________________________________________________________________________ + + _check(pp) + #_________________________________________________________________________________________ + + _conl(_report(pp)) + _wrfile("report.txt", _report(pp)) +} + +######################################################### + +function _SYSIO(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": return - hh = "CPU" - _conl("go1!") - _conl(_var(_sharepath(hh, "gdfsgdsgsd sdgsdighjui teretiewrotrewut 345345345 rtjtireutireu huj"))) - _conl("go2!") - _conl(_var(_sharelist(AAA, hh), _dumparr(AAA))) - _conline() - A[1] = "h" - A[3] = "j" - t = "pizda" - if (match(t, /^pi(Z)da/, A)) { - _conl("match") - } else { - _conl("not match") - } - _conl(_dumparr(A)) + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_SYSIO 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": return - _pathSMA = "C:\\Program Files\\Altiris\\Altiris Agent\\" - DSPlugInPath = _pathSMA "Agents\\Deployment\\Agent\\" - DSAutoPath = _pathSMA - if (! _sysinfo(_SYS, _hostname)) { - _fatal("_sysinfo: unknown error") - } - _REG[""] - delete _REG[""] - _servoutput = _CHR["EOL"] _cmd("sc query state= all") - _dsbasepath = "\\\\CPU\\CPU\\DEV\\PROJECT\\_DS\\" - _rdreg(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris") - _wrfile("rego.txt", _dumparr(_REG)) - _conl("fF") - c = _getreg_i1(DDD, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\\204~.*\224Install path", _REG) - pp = _n("NAME", "NS") - p = _defsolution(pp, "DS Plug-in", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") - ClientConfiguration = _defdll(p, "Client Configuration", "ClientConfiguration") - ClientImagingPrep = _defdll(p, "Client Inaging Preparation", "ClientImagingPrep") - ClientImaging = _defdll(p, "Client Imaging", "ClientImaging") - ClientPCT = _defdll(p, "Client PCT", "ClientPCT") - ClientRebootTo = _defdll(p, "Client Reboot To", "ClientRebootTo") - DeploymentAgent = _defdll(p, "Deployment Agent", "Deployment Agent") - DeploymentSolutionBaseAgent = _defdll(p, "Deployment Solution Base Agent", "Deployment Solution Base Agent") - ClientBCDEdit = _defile(p, "Client BCD Edit", "ClientBCDEdit.dll") - ClientCopyFile = _defile(p, "Client Copy File", "ClientCopyFile.dll") - ClientPreImage = _defile(p, "Client Pre Image", "ClientPreImage.dll") - ClientRebootTo = _defile(p, "Client Reboot To", "ClientRebootTo.dll") - _defile(p, "ConfigService.exe", "ConfigService.exe", "") - _defile(p, "config.dll", "config.dll", "") - _defsrv(p, "DS Plug-in Service", "Altiris Deployment Solution - System Configuration") - _defreg(p, "Deployment Agent Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR") - _defile(p, "Altiris_DeploymentSolutionAgent_7_1_x86.msi", (_SYS["OSArchitecture"] == "64-bit" ? "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{9D76E4CA-377A-472D-A82E-EDAD77E7E4ED}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x64.msi" : "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{4B747D25-612F-48FC-B6B5-9916D1BB755C}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x86.msi"), "") - _defdir(p, "Deployment Folder", a = gensub(/[^\\]*$/, "", 1, _rdsafe(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR", "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\Deployment\\Agent\\"))) - p = _defsolution(pp, "DS Auto", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") - _defdir(p, "C:\\Boot\\Altiris\\iso\\boot\\fonts\\", "C:\\Boot\\Altiris\\iso\\boot\\fonts\\") - _defdir(p, "C:\\Boot\\Altiris\\iso\\sources\\", "C:\\Boot\\Altiris\\iso\\sources\\") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.exe", "C:\\Boot\\Altiris\\iso\\autoinst.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.ini", "C:\\Boot\\Altiris\\iso\\autoinst.ini", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.exe", "C:\\Boot\\Altiris\\iso\\autoutil.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.ini", "C:\\Boot\\Altiris\\iso\\autoutil.ini", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bootmgr", "C:\\Boot\\Altiris\\iso\\bootmgr", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bootsect.exe", "C:\\Boot\\Altiris\\iso\\bootsect.exe", "") - _defreg(p, "Deployment Automation reg.File", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\File.XSZ", "autoutil.exe") - _defreg(p, "Deployment Automation reg.Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\Path.XSZ", "%systemdrive%\\boot\\altiris\\iso") - _check(pp) - _conl(_report(pp)) - _wrfile("report.txt", _report(pp)) - } - - function _SYSIO(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_SYSIO 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - } } +} - function _W(p, A, v) - { - if (isarray(v)) { - if (p) { - delete A[p] - A[p][""] - delete A[p][""] - _movarr(A[p], v) - } - return p - } +#_______________________________________________________________________ +######################################################################## + + +function _W(p, A, v) +{ + if (isarray(v)) { if (p) { delete A[p] - return (A[p] = v) + A[p][""] + delete A[p][""] + _movarr(A[p], v) } - return v + return p } - - function _Zexparr(S, s, t, i) - { - t = "" - if (isarray(S)) { - for (i in S) { - t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) - } - } - if (s != "") { - gsub(/\x1B/, "\033;", s) - gsub(/\x10/, "\0330", s) - t = t "\021\021\020" s - } - gsub(/\x0A/, "\033:", t) - return t + if (p) { + delete A[p] + return (A[p] = v) } + return v +} - function _Zexparr_i0(S, t, i) - { +#_______________________________________________________________________ +function _Zexparr(S, s, t, i) +{ + ############################################## + t = "" + if (isarray(S)) { for (i in S) { t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) } - return t - } - - function _Zexparr_i1(t) - { - gsub(/\x1B/, "\033;", t) - gsub(/\x11/, "\0331", t) - gsub(/\x10/, "\0330", t) - return t } - - function _Zexparr_i2(t) - { - gsub(/\x10/, "\0330", t) + if (s != "") { + gsub(/\x1B/, "\033;", s) + gsub(/\x10/, "\0330", s) + t = t "\021\021\020" s + } + gsub(/\x0A/, "\033:", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i0(S, t, i) +{ + for (i in S) { + t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) + } + return t +} + +#_________________________________________________________________ +function _Zexparr_i1(t) +{ + gsub(/\x1B/, "\033;", t) + gsub(/\x11/, "\0331", t) + gsub(/\x10/, "\0330", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i2(t) +{ + gsub(/\x10/, "\0330", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i3(t) +{ + gsub(/\x1B/, "\033;", t) + gsub(/\x11/, "\0331", t) + return t +} + +#_______________________________________________________________________ +function _Zimparr(D, t, A, B) +{ + ############################################## + if (isarray(D)) { + split(t, A, /\x10/, B) + t = _Zimparr_i0(A, B, _Zimparr_i1(D, A, B, 1)) + gsub(/\x1B\x30/, "\020", t) + gsub(/\x1B\x3B/, "\033", t) return t } +} - function _Zexparr_i3(t) - { - gsub(/\x1B/, "\033;", t) - gsub(/\x11/, "\0331", t) - return t - } +#_________________________________________________________________ +function _Zimparr_i0(A, B, i) +{ + return ((i in A ? A[i] B[i] _Zimparr_i0(A, B, i + 1) : "")) +} - function _Zimparr(D, t, A, B) - { - if (isarray(D)) { - split(t, A, /\x10/, B) - t = _Zimparr_i0(A, B, _Zimparr_i1(D, A, B, 1)) - gsub(/\x1B\x30/, "\020", t) - gsub(/\x1B\x3B/, "\033", t) - return t +#_________________________________________________________________ +function _Zimparr_i1(D, A, B, i, t, a, n) +{ + while (i in B) { + if ((t = A[i++]) == "\021\021") { + return i } - } - - function _Zimparr_i0(A, B, i) - { - return ((i in A ? A[i] B[i] _Zimparr_i0(A, B, i + 1) : "")) - } - - function _Zimparr_i1(D, A, B, i, t, a, n) - { - while (i in B) { - if ((t = A[i++]) == "\021\021") { - return i + gsub(/\x1B\x30/, "\020", t) + if ((a = index(t, "\021")) > 0) { + if (isarray(D[n = _Zimparr_i2(substr(t, 1, a - 1))])) { + delete D[n] } - gsub(/\x1B\x30/, "\020", t) - if ((a = index(t, "\021")) > 0) { - if (isarray(D[n = _Zimparr_i2(substr(t, 1, a - 1))])) { - delete D[n] - } - D[n] = _Zimparr_i2(substr(t, a + 1)) + D[n] = _Zimparr_i2(substr(t, a + 1)) + } else { + if (! isarray(D[t = _Zimparr_i2(t)])) { + delete D[t] + D[t][""] + delete D[t][""] + } + i = _Zimparr_i1(D[t], A, B, i) + } + } +} + +#_________________________________________________________________ +function _Zimparr_i2(t) +{ + gsub(/\x1B\x31/, "\021", t) + gsub(/\x1B\x3B/, "\033", t) + return t +} + +#_____________________________________________________________________________ +function _Zimport(t, p, A, c, i, n, B) +{ + ############################################## + if (p) { + c = split(t, B, /\x0A/) + for (i = 1; i <= c; i++) { + if ((t = B[i]) == "") { + continue + } + gsub(/\x1B\x3A/, "\n", t) + if (match(t, /^_ERRLOG: /)) { + _tLOG[n = _wLCHLD(p, _N())][""] + delete _tLOG[n][""] + _Zimparr(_tLOG[n], substr(t, 10)) } else { - if (! isarray(D[t = _Zimparr_i2(t)])) { - delete D[t] - D[t][""] - delete D[t][""] + if ((t = _pass(_IMPORT, t, p, A)) != "") { + gsub(/\x1B\x3B/, "\033", t) + _wLCHLD(p, _N(_tSTR, t)) } - i = _Zimparr_i1(D[t], A, B, i) } } - } - - function _Zimparr_i2(t) - { - gsub(/\x1B\x31/, "\021", t) - gsub(/\x1B\x3B/, "\033", t) - return t - } - - function _Zimport(t, p, A, c, i, n, B) - { - if (p) { - c = split(t, B, /\x0A/) - for (i = 1; i <= c; i++) { - if ((t = B[i]) == "") { - continue - } - gsub(/\x1B\x3A/, "\n", t) - if (match(t, /^_ERRLOG: /)) { - _tLOG[n = _wLCHLD(p, _N())][""] - delete _tLOG[n][""] - _Zimparr(_tLOG[n], substr(t, 10)) + return p + } else { + _expout(t) + } +} + +function _acc(A, a, t) +{ + if (t) { + if (_VLDMAXSTRING < length(t) + length(a)) { + if (a) { + if (_VLDMAXSTRING < length(t)) { + A[--A[_ARRPTR]] = a + A[--A[_ARRPTR]] = t } else { - if ((t = _pass(_IMPORT, t, p, A)) != "") { - gsub(/\x1B\x3B/, "\033", t) - _wLCHLD(p, _N(_tSTR, t)) - } + A[--A[_ARRPTR]] = a t } + } else { + A[++A[_ARRLEN]] = t } - return p - } else { - _expout(t) + return "" } + return (a t) } + return a +} - function _acc(A, a, t) - { - if (t) { - if (_VLDMAXSTRING < length(t) + length(a)) { - if (a) { - if (_VLDMAXSTRING < length(t)) { - A[--A[_ARRPTR]] = a - A[--A[_ARRPTR]] = t - } else { - A[--A[_ARRPTR]] = a t - } - } else { - A[++A[_ARRLEN]] = t - } - return "" - } - return (a t) - } - return a +function _accmpu(A, a, n) +{ + if (n) { + return (_mpufn0 = n) } - - function _accmpu(A, a, n) - { - if (n) { - return (_mpufn0 = n) - } - if (_mpuacc) { - if (_VLDMAXSTRING < length(_mpuacc) + length(a)) { - if (a) { - if (_VLDMAXSTRING < length(_mpuacc)) { - A[--A[_ARRLEN]] = a - A[--A[_ARRLEN]] = _mpuacc - } else { - A[--A[_ARRLEN]] = a _mpuacc - } - } else { + if (_mpuacc) { + if (_VLDMAXSTRING < length(_mpuacc) + length(a)) { + if (a) { + if (_VLDMAXSTRING < length(_mpuacc)) { + A[--A[_ARRLEN]] = a A[--A[_ARRLEN]] = _mpuacc + } else { + A[--A[_ARRLEN]] = a _mpuacc } - _mpuacc = "" } else { - _mpuacc = a _mpuacc + A[--A[_ARRLEN]] = _mpuacc } + _mpuacc = "" } else { - _mpuacc = a + _mpuacc = a _mpuacc } + } else { + _mpuacc = a } +} - function _add(S, sf, D, df) - { - if (sf in S) { - if (isarray(S[sf])) { - if (df in D) { - if (isarray(D[df])) { - return _extarr(D[df], S[sf]) - } - delete D[df] - } - D[df][""] - delete D[df][""] - return _extarr(D[df], S[sf]) - } else { +#_______________________________________________________________________ +function _add(S, sf, D, df) +{ + ################################################ + if (sf in S) { + if (isarray(S[sf])) { + if (df in D) { if (isarray(D[df])) { - delete D[df] + return _extarr(D[df], S[sf]) } - D[df] = D[df] S[sf] + delete D[df] } + D[df][""] + delete D[df][""] + return _extarr(D[df], S[sf]) + } else { + if (isarray(D[df])) { + delete D[df] + } + D[df] = D[df] S[sf] } } +} - function _addarr(D, S) - { - if (isarray(S)) { - _addarr_i0(D, S) - } - } - - function _addarr_i0(D, S, i) - { - for (i in S) { - if (isarray(S[i])) { - delete D[i] - D[i][""] - delete D[i][""] - _addarr_i0(D[i], S[i]) - } else { - delete D[i] - D[i] = S[i] - } - } +#_________________________________________________________________ +function _addarr(D, S) +{ + ############################################# + if (isarray(S)) { + _addarr_i0(D, S) } +} - function _addarrmask(D, S, M) - { - for (_addarrmaski0 in M) { - if (_addarrmaski0 in S) { - if (isarray(S[_addarrmaski0])) { - if (! isarray(D[_addarrmaski0])) { - delete D[_addarrmaski0] - D[_addarrmaski0][""] - delete D[_addarrmaski0][""] - } - if (isarray(M[_addarrmaski0])) { - _addarrmask(D[_addarrmaski0], S[_addarrmaski0], M[_addarrmaski0]) - } else { - _extarr_i0(D[_addarrmaski0], S[_addarrmaski0]) - } +#_____________________________________________________ +function _addarr_i0(D, S, i) +{ + for (i in S) { + if (isarray(S[i])) { + delete D[i] + D[i][""] + delete D[i][""] + _addarr_i0(D[i], S[i]) + } else { + delete D[i] + D[i] = S[i] + } + } +} + +#_______________________________________________________________________ +function _addarrmask(D, S, M) +{ + ############################################# + for (_addarrmaski0 in M) { + if (_addarrmaski0 in S) { + if (isarray(S[_addarrmaski0])) { + if (! isarray(D[_addarrmaski0])) { + delete D[_addarrmaski0] + D[_addarrmaski0][""] + delete D[_addarrmaski0][""] + } + if (isarray(M[_addarrmaski0])) { + _addarrmask(D[_addarrmaski0], S[_addarrmaski0], M[_addarrmaski0]) } else { - if (isarray(D[_addarrmaski0])) { - delete D[_addarrmaski0] - } - D[_addarrmaski0] = S[_addarrmaski0] + _extarr_i0(D[_addarrmaski0], S[_addarrmaski0]) } } else { - delete D[_addarrmaski0] + if (isarray(D[_addarrmaski0])) { + delete D[_addarrmaski0] + } + D[_addarrmaski0] = S[_addarrmaski0] } + } else { + delete D[_addarrmaski0] } } +} - function _addf(A, f) - { - A["B"][""] = A["F"][A["B"][f] = A["B"][""]] = f - } +#___________________________________________________________________________________ +#################################################################################### - function _addfile(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" - ERRNO = "" - print(d) >> f - if (ERRNO) { - return "" - } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" - } - return d - } - function _addlib(f) - { - _addf(_LIBAPI, f) - } +#_______________________________________________________________________ +function _addf(A, f) +{ + ##################################################### + A["B"][""] = A["F"][A["B"][f] = A["B"][""]] = f +} - function _addlist(A, v) - { - A[++A[0]] = v +#___________________________________________________________ +function _addfile(f, d, a, b) +{ + ################################## + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function _bearray(A) - { - if (isarray(A) || A == 0 && A == "") { - return 1 - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) >> f + if (ERRNO) { + return "" } - - function _bframe(A, t, p) - { - return _bframe_i0(A, t, p, A[""]) + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" } - - function _bframe_i0(A, t, p, f) - { - return ((f ? _bframe_i0(A, t, p, A[f]) (@f(t, p)) : "")) + return d +} + +#_____________________________________________________________________________ +function _addlib(f) +{ + ########################################################### + _addf(_LIBAPI, f) +} + +#___________________________________________________________________________________ +#################################################################################### + + +#_______________________________________________________________________ +function _addlist(A, v) +{ + ################################################## + A[++A[0]] = v +} + +############################################ +#_______________________________________________________________________ +function _bearray(A) +{ + #################################################### + if (isarray(A) || A == 0 && A == "") { + return 1 } +} - function _cfguid(p, optr, pfx, sfx, hstrcnt, lstrchr) - { - delete _UIDOBL[p] - if (_isptr(optr)) { - if (optr == p) { - delete _UIDOBLV[p] - delete _UIDOBLV[_UIDOBLV[_UIDOBL[p] = p][""] = p][""] - } else { - if (optr in _UIDOBL) { - _UIDOBL[p] = _UIDOBL[optr] - } - } - } - _UIDPFX[p] = (_istr(pfx) ? pfx : "") - _UIDSFX[p] = (_istr(sfx) ? sfx : "") - if (_isptr(hstrcnt)) { - if (hstrcnt != p) { - _UIDCHR[p] = _UIDCHR[_UIDCNT[p] = _UIDCNT[hstrcnt]] - return p - } - hstrcnt = _NOP - } - _UIDCNTL[_UIDCNT[p] = p] = _cfguidchr(p, hstrcnt, lstrchr) - return p - } +#_________________________________________________________________ +function _bframe(A, t, p) +{ + ########################################### + return _bframe_i0(A, t, p, A[""]) +} - function _cfguidchr(p, h, l, H, L) - { - if (_isptr(l)) { - if (l != p) { - return (_UIDCHR[p] = _UIDCHR[l]) - } - _UIDCHR[p] = p - l = _NOP - } - _UIDCHR[p] = p - _splitstr(H, h, _UIDCHRH[_classys]) - _splitstr(L, l, H) - delete _UIDCHRH[_UIDCHRH[p][""] = p][""] - delete _UIDCHRL[_UIDCHRL[p][""] = p][""] - _cfguidh(p, H, L) - return _cfguidl(p, L, L) - } - - function _cfguidh(p, H, L, hi, h, li) - { - for (hi = 1; hi in H; hi++) { - h = H[hi] - for (li = 1; li in L; li++) { - _UIDCHRH[p][h L[li]] - } - } - } +#___________________________________________________________ +function _bframe_i0(A, t, p, f) +{ + return ((f ? _bframe_i0(A, t, p, A[f]) (@f(t, p)) : "")) +} - function _cfguidl(p, H, L, hi, h, hl, li) - { - for (hi = 1; hi in H; hi++) { - h = H[hi] - for (li = 1; li in L; li++) { - hl = _UIDCHRL[p][hl] = h L[li] - } - } - return hl - } +# add to _dumparr: checking that if element is undefined - function _check(p) - { - _dll_check(p) - _file_check(p) - _serv_check(p) - _reg_check(p) - } - function _chrline(t, ts, w, s) - { - return ((t = " " _tabtospc(t, ts) ((t ? (t ~ /[ \t]$/ ? "" : " ") : ""))) _getchrln((s ? s : "_"), ((w ? w : _CON_WIDTH - 1)) - length(t)) _CHR["EOL"]) - } - function _cmd(c, i, A) - { - _fio_cmda = RS - RS = ".{1,}" - _fio_cmdb = BINMODE - BINMODE = "rw" - ERRNO = RT = _NUL - c | getline RS - BINMODE = _fio_cmdb - RS = _fio_cmda - if (ERRNO || 0 > (_exitcode = close(c))) { - return (RT = _NOP) - } - return RT - } - function _cmparr(A0, A1, R, a, i) - { - a = 0 - delete R - for (i in A0) { - if (! (i in A1)) { - a++ - R[i] = 0 - } else { - if (A0[i] != A1[i]) { - a++ - R[i] = 2 - } - } - } - for (i in A1) { - if (! (i in A0)) { - a++ - R[i] = 1 - } - } - return a - } - function _con(t, ts, a, b, c, d, i, r, A, B) - { - d = RLENGTH - if ((c = split(r = t, A, /\x0D?\x0A/, B)) > 0) { - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - if (c > 1) { - if ((i = length(t = _tabtospc(A[1], ts, _conlastrln))) < _constatstrln) { - t = t _getchrln(" ", _constatstrln - i) - } - print(t B[1]) > _SYS_STDCON - for (i = 2; i < c; i++) { - print(_tabtospc(A[i], ts) B[i]) > _SYS_STDCON - } - print(_conlastr = _tabtospc(A[c], ts)) > _SYS_STDCON - fflush(_SYS_STDCON) - } else { - print(t = _tabtospc(t, ts, _conlastrln)) > _SYS_STDCON - fflush(_SYS_STDCON) - _conlastr = _conlastr t - } - if ((i = length(_conlastr)) >= _CON_WIDTH) { - _conlastr = substr(_conlastr, 1 + int(i / _CON_WIDTH) * _CON_WIDTH) - } - _conlastrln = length(_conlastr) - if (_constatstr) { - print((t = _constatgtstr(_constatstr, _CON_WIDTH - 1 - _conlastrln)) _CHR["CR"] _conlastr) > _SYS_STDCON - fflush(_SYS_STDCON) - _constatstrln = length(t) - } - BINMODE = a - ORS = b - RLENGTH = d - return r - } - RLENGTH = d - } - function _conin(t, a, b) - { - _constatpush() - _constat() - a = BINMODE - b = RS - BINMODE = "rw" - RS = "\n" - _con(t) - getline t < "CON" - close("CON") - _conlastrln = 0 - _conlastr = "" - gsub(/[\x0D\x0A]+/, "", t) - BINMODE = a - RS = b - _constatpop() - return t - } - function _conl(t, ts) - { - return _con(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"])), ts) - } - function _conline(t, ts) - { - return _con(_chrline(t, ts)) - } - function _conlq(t, ts) - { - return _conl("`" t "'", ts) - } - function _constat(t, ts, ln, a) - { - if (_constatstrln > (ln = length(t = _constatgtstr(_constatstr = _tabtospc(t, ts), _CON_WIDTH - 1 - _conlastrln)))) { - t = t _getchrln(" ", _constatstrln - ln) - } - _constatstrln = ln - ln = ORS - a = BINMODE - BINMODE = "rw" - ORS = "" - print(t _CHR["CR"] _conlastr) > _SYS_STDCON - fflush(_SYS_STDCON) - ORS = ln - BINMODE = a - return _constatstr - } - function _constatgtstr(t, ln, a, b) - { - if (ln < 1) { - return "" - } - if ((a = length(t)) <= ln) { - return t - } - if (ln < 11) { - return substr(t, a - ln + 1) - } - if (ln < 19) { - return ("..." substr(t, a - ln + 4)) - } - return (substr(t, 1, b = int((ln - 3) / 2)) "..." substr(t, a - ln + b + 4)) - } - function _constatpop() - { - if (_CONSTATPUSH[0] > 0) { - return _constat(_CONSTATPUSH[_CONSTATPUSH[0]--]) - } - return _constat("") - } - function _constatpush(t, ts) - { - _CONSTATPUSH[++_CONSTATPUSH[0]] = _constatstr - if (t) { - _constat(t, ts) - } - return _constatstr - } - function _creport(p, t, f, z) - { - _[p]["REPORT"] = _[p]["REPORT"] _ln(t ((f == "" ? "" : ": " f))) - } - function _defdir(pp, n, f, v, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "defdir"))]["NAME"] = n - _[p]["DIR"] = f - return p - } - function _defdll(pp, n, rn, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "defdll"))]["NAME"] = n - _[p]["REGPATH"] = _[pp]["REGPATH"] rn - _[p]["ERRHOST"] = pp - return p - } - function _defescarr(D, r, S, i, c, t) - { - if (isarray(S)) { - for (i = 0; i < 256; i++) { - if ((c = _CHR[i]) ~ r) { - D[c] = "\\" S[c] - t = t c - } else { - if (D[c] == "") { - D[c] = c - } - } - } + +#_______________________________________________________________________ +function _cfguid(p, optr, pfx, sfx, hstrcnt, lstrchr) +{ + #################### 0 # + delete _UIDOBL[p] + if (_isptr(optr)) { + if (optr == p) { + delete _UIDOBLV[p] + delete _UIDOBLV[_UIDOBLV[_UIDOBL[p] = p][""] = p][""] } else { - for (i = 0; i < 256; i++) { - if ((c = _CHR[i]) ~ r) { - D[c] = S c - if (S != "") { - t = t c - } - } else { - if (D[c] == "") { - D[c] = c - } - } + if (optr in _UIDOBL) { + _UIDOBL[p] = _UIDOBL[optr] } } - return t } - - function _defile(pp, n, f, v, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "defile"))]["NAME"] = n - _[p]["FILE"] = f - if (! (v == 0 && v == "")) { - _[p]["RQVERSION"] = v + _UIDPFX[p] = (_istr(pfx) ? pfx : "") + _UIDSFX[p] = (_istr(sfx) ? sfx : "") + if (_isptr(hstrcnt)) { + if (hstrcnt != p) { + _UIDCHR[p] = _UIDCHR[_UIDCNT[p] = _UIDCNT[hstrcnt]] + return p } - return p + hstrcnt = _NOP } + _UIDCNTL[_UIDCNT[p] = p] = _cfguidchr(p, hstrcnt, lstrchr) + return p +} - function _defn(f, c, v) - { - FUNCTAB[c f] = v - } - - function _defreg(pp, n, f, v, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "defreg"))]["NAME"] = n - _[p]["REGPATH"] = f - if (! (v == 0 && v == "")) { - _[p]["VALUE"] = v +#_____________________________________________________ +function _cfguidchr(p, h, l, H, L) +{ + if (_isptr(l)) { + if (l != p) { + return (_UIDCHR[p] = _UIDCHR[l]) } + _UIDCHR[p] = p + l = _NOP + } + _UIDCHR[p] = p + _splitstr(H, h, _UIDCHRH[_classys]) + _splitstr(L, l, H) + delete _UIDCHRH[_UIDCHRH[p][""] = p][""] + delete _UIDCHRL[_UIDCHRL[p][""] = p][""] + _cfguidh(p, H, L) + return _cfguidl(p, L, L) +} + +#_______________________________________________ +function _cfguidh(p, H, L, hi, h, li) +{ + for (hi = 1; hi in H; hi++) { + h = H[hi] + for (li = 1; li in L; li++) { + _UIDCHRH[p][h L[li]] + } + } +} + +function _cfguidl(p, H, L, hi, h, hl, li) +{ + for (hi = 1; hi in H; hi++) { + h = H[hi] + for (li = 1; li in L; li++) { + hl = _UIDCHRL[p][hl] = h L[li] + } + } + return hl +} + +#____________________________________________________________________________________________________ +function _check(p) +{ + #################################################################################### + _dll_check(p) + _file_check(p) + _serv_check(p) + _reg_check(p) +} + +#_______________________________________________________________________ +function _chrline(t, ts, w, s) +{ + ############################################# + return ((t = " " _tabtospc(t, ts) ((t ? (t ~ /[ \t]$/ ? "" : " ") : ""))) _getchrln((s ? s : "_"), ((w ? w : _CON_WIDTH - 1)) - length(t)) _CHR["EOL"]) +} + +#_____________________________________________________________________________ +function _cmd(c, i, A) +{ + ####################################################### + _fio_cmda = RS + RS = ".{1,}" + _fio_cmdb = BINMODE + BINMODE = "rw" + ERRNO = RT = _NUL + c | getline RS + BINMODE = _fio_cmdb + RS = _fio_cmda + if (ERRNO || 0 > (_exitcode = close(c))) { + return (RT = _NOP) } - - function _defsolution(pp, n, rn, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "solution"))]["NAME"] = n - _[p]["REGPATH"] = rn - _[p]["ERRHOST"] = pp - return p - } - - function _defsrv(pp, n, f, v, p) - { - _[p = _wLCHLD(pp, _n("TYPE", "defsrv"))]["NAME"] = n - _[p]["SERVNAME"] = f - return p - } - - function _del(f, c, a, A) - { - if (match(f, /\\[ \t]*$/)) { - if ((c = toupper(_filerd(f))) && length(f) == FLENGTH) { - _cmd("rd " c " /S /Q 2>NUL") - _deletepfx(_WFILEROOTDIR, c) - _deletepfx(_FILEIO_RDTMP, c) - _deletepfx(_FILEIO_RDNETMP, c) - } else { - _conl("HUJ TEBE!") - return "" - } + return RT +} + +#_______________________________________________________________________ +function _cmparr(A0, A1, R, a, i) +{ + ########################################## + a = 0 + delete R + for (i in A0) { + if (! (i in A1)) { + a++ + R[i] = 0 } else { - a = _dir(A, f) - _cmd("del " f " /Q 2>NUL") - for (c in A) { - if (c ~ /\\$/) { - _cmd("rd " c " /S /Q 2>NUL") - _deletepfx(_WFILEROOTDIR, c) - _deletepfx(_FILEIO_RDTMP, c) - } - _deletepfx(_FILEIO_RDNETMP, c) + if (A0[i] != A1[i]) { + a++ + R[i] = 2 } } - return a } - - function _delay(t, a) - { - for (a = 1; a <= t; a++) { - _delayms() - } - } - - function _delayms(a) - { - for (a = 1; a <= _delay_perfmsdelay; a++) { + for (i in A1) { + if (! (i in A0)) { + a++ + R[i] = 1 } } + return a +} - function _deletepfx(A, f, B, le, i) - { - le = length(f) - for (i in A) { - if (substr(toupper(i), 1, le) == f) { - B[i] = A[i] - delete A[i] +#_____________________________________________________________________________ +function _con(t, ts, a, b, c, d, i, r, A, B) +{ + ########################################## + d = RLENGTH + if ((c = split(r = t, A, /\x0D?\x0A/, B)) > 0) { + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + if (c > 1) { + if ((i = length(t = _tabtospc(A[1], ts, _conlastrln))) < _constatstrln) { + t = t _getchrln(" ", _constatstrln - i) } + print(t B[1]) > _SYS_STDCON + for (i = 2; i < c; i++) { + print(_tabtospc(A[i], ts) B[i]) > _SYS_STDCON + } + print(_conlastr = _tabtospc(A[c], ts)) > _SYS_STDCON + fflush(_SYS_STDCON) + } else { + print(t = _tabtospc(t, ts, _conlastrln)) > _SYS_STDCON + fflush(_SYS_STDCON) + _conlastr = _conlastr t + } + if ((i = length(_conlastr)) >= _CON_WIDTH) { + _conlastr = substr(_conlastr, 1 + int(i / _CON_WIDTH) * _CON_WIDTH) } + _conlastrln = length(_conlastr) + if (_constatstr) { + print((t = _constatgtstr(_constatstr, _CON_WIDTH - 1 - _conlastrln)) _CHR["CR"] _conlastr) > _SYS_STDCON + fflush(_SYS_STDCON) + _constatstrln = length(t) + } + BINMODE = a + ORS = b + RLENGTH = d + return r } - - function _delf(A, f) - { - A["B"][A["F"][A["B"][f]] = A["F"][f]] = A["B"][f] - delete A["F"][f] - delete A["B"][f] + RLENGTH = d +} + +#_______________________________________________________________________ +function _conin(t, a, b) +{ + ################################################# + _constatpush() + _constat() + a = BINMODE + b = RS + BINMODE = "rw" + RS = "\n" + _con(t) + getline t < "CON" + close("CON") + _conlastrln = 0 + _conlastr = "" + gsub(/[\x0D\x0A]+/, "", t) + BINMODE = a + RS = b + _constatpop() + return t +} + +#_______________________________________________________________________ +function _conl(t, ts) +{ + #################################################### + return _con(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"])), ts) +} + +#_______________________________________________________________________ +function _conline(t, ts) +{ + ################################################# + return _con(_chrline(t, ts)) +} + +#___________________________________________________________________________________ +#################################################################################### + + + +function _conlq(t, ts) +{ + return _conl("`" t "'", ts) +} + +#_______________________________________________________________________ +function _constat(t, ts, ln, a) +{ + ########################################### + if (_constatstrln > (ln = length(t = _constatgtstr(_constatstr = _tabtospc(t, ts), _CON_WIDTH - 1 - _conlastrln)))) { + t = t _getchrln(" ", _constatstrln - ln) + } + _constatstrln = ln + ln = ORS + a = BINMODE + BINMODE = "rw" + ORS = "" + print(t _CHR["CR"] _conlastr) > _SYS_STDCON + fflush(_SYS_STDCON) + ORS = ln + BINMODE = a + return _constatstr +} + +#_________________________________________________________________ +function _constatgtstr(t, ln, a, b) +{ + if (ln < 1) { + return "" } - - function _deluid(p) - { - if (p in _CLASSPTR) { - _deluida0 = _CLASSPTR[p] - if (_deluida0 in _UIDOBL) { - _UIDOBLV[_UIDOBL[_deluida0]][p] - } - } - delete _CLASSPTR[p] - return _deluida0 + if ((a = length(t)) <= ln) { + return t } - - function _dir(A, rd, i, r, f, ds, pf, B, C) - { - delete A - gsub(/(^[ \t]*)|([ \t]*$)/, "", rd) - if (rd == "") { - return "" + if (ln < 11) { + return substr(t, a - ln + 1) + } + if (ln < 19) { + return ("..." substr(t, a - ln + 4)) + } + return (substr(t, 1, b = int((ln - 3) / 2)) "..." substr(t, a - ln + b + 4)) +} + +#_______________________________________________________________________ +function _constatpop() +{ + ################################################## + if (_CONSTATPUSH[0] > 0) { + return _constat(_CONSTATPUSH[_CONSTATPUSH[0]--]) + } + return _constat("") +} + +#_______________________________________________________________________ +function _constatpush(t, ts) +{ + ############################################# + _CONSTATPUSH[++_CONSTATPUSH[0]] = _constatstr + if (t) { + _constat(t, ts) + } + return _constatstr +} + +#___________________________________________________________________________________ +function _creport(p, t, f, z) +{ + _[p]["REPORT"] = _[p]["REPORT"] _ln(t ((f == "" ? "" : ": " f))) +} + +#_________________________________________________________________________________________ +function _defdir(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defdir"))]["NAME"] = n + _[p]["DIR"] = f + return p +} + +#_________________________________________________________________________________________ +function _defdll(pp, n, rn, p) +{ + ############################################################## + _[p = _wLCHLD(pp, _n("TYPE", "defdll"))]["NAME"] = n + _[p]["REGPATH"] = _[pp]["REGPATH"] rn + _[p]["ERRHOST"] = pp + return p +} + +#___________________________________________________________ +function _defescarr(D, r, S, i, c, t) +{ + if (isarray(S)) { + for (i = 0; i < 256; i++) { + if ((c = _CHR[i]) ~ r) { + D[c] = "\\" S[c] + t = t c + } else { + if (D[c] == "") { + D[c] = c + } + } } - i = split(_cmd("dir \"" rd "\" 2>NUL"), B, /\x0D?\x0A/) - 3 - pf = (match(B[4], /Directory of ([^\x00-\x1F]+)/, C) ? C[1] ((C[1] ~ /\\$/ ? "" : "\\")) : "") - for (r = 0; i > 5; i--) { - if (match(B[i], /^([^ \t]*)[ \t]+([^ \t]*)[ \t]+((<DIR>)|([0-9\,]+))[ \t]+([^\x00-\x1F]+)$/, C)) { - if (C[6] !~ /^\.\.?$/) { - if (C[4]) { - ds = "D " - } else { - ds = C[5] " " - gsub(/\,/, "", ds) - } - if ((f = _filepath(pf C[6] ((C[4] ? "\\" : "")))) != "") { - A[f] = ds C[1] " " C[2] - r++ - } + } else { + for (i = 0; i < 256; i++) { + if ((c = _CHR[i]) ~ r) { + D[c] = S c + if (S != "") { + t = t c + } + } else { + if (D[c] == "") { + D[c] = c } } } - return r } - - function _dirtree(A, f, B) - { - gsub(/(^[ \t]*)|([ \t]*$)/, "", f) - delete A - A[""] - delete A[""] - _dirtree_i0(B, 8, split(_cmd("dir \"" f "\" /-C /S 2>NUL"), B, /\x0D?\x0A/), A, f = _filerd(f)) - return f + return t +} + +#_________________________________________________________________________________________ +function _defile(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defile"))]["NAME"] = n + _[p]["FILE"] = f + if (! (v == 0 && v == "")) { + _[p]["RQVERSION"] = v + } + return p +} + +#_______________________________________________________________________ +function _defn(f, c, v) +{ + ################################################### + FUNCTAB[c f] = v +} + +#_________________________________________________________________________________________ +function _defreg(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defreg"))]["NAME"] = n + _[p]["REGPATH"] = f + if (! (v == 0 && v == "")) { + _[p]["VALUE"] = v + } +} + +#_______________________________________________________________________________________________ +function _defsolution(pp, n, rn, p) +{ + ############################################################### + _[p = _wLCHLD(pp, _n("TYPE", "solution"))]["NAME"] = n + _[p]["REGPATH"] = rn + _[p]["ERRHOST"] = pp + return p +} + +#_________________________________________________________________________________________ +function _defsrv(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defsrv"))]["NAME"] = n + _[p]["SERVNAME"] = f + return p +} + +#_______________________________________________________________________ +function _del(f, c, a, A) +{ + ################################################# + if (match(f, /\\[ \t]*$/)) { + if ((c = toupper(_filerd(f))) && length(f) == FLENGTH) { + _cmd("rd " c " /S /Q 2>NUL") + _deletepfx(_WFILEROOTDIR, c) + _deletepfx(_FILEIO_RDTMP, c) + _deletepfx(_FILEIO_RDNETMP, c) + } else { + _conl("HUJ TEBE!") + return "" + } + } else { + a = _dir(A, f) + _cmd("del " f " /Q 2>NUL") + for (c in A) { + if (c ~ /\\$/) { + _cmd("rd " c " /S /Q 2>NUL") + _deletepfx(_WFILEROOTDIR, c) + _deletepfx(_FILEIO_RDTMP, c) + } + _deletepfx(_FILEIO_RDNETMP, c) + } + } + return a +} + +#_______________________________________________________________________ +function _delay(t, a) +{ + ################################################### + for (a = 1; a <= t; a++) { + _delayms() + } +} + +#_________________________________________________________________ +function _delayms(a) +{ + ############################################# + for (a = 1; a <= _delay_perfmsdelay; a++) { + } +} + +#_______________________________________________________________________ +function _deletepfx(A, f, B, le, i) +{ + ######################################## + le = length(f) + for (i in A) { + if (substr(toupper(i), 1, le) == f) { + B[i] = A[i] + delete A[i] + } + } +} + +#_________________________________________________________________ +function _delf(A, f) +{ + ############################################### + A["B"][A["F"][A["B"][f]] = A["F"][f]] = A["B"][f] + delete A["F"][f] + delete A["B"][f] +} + +#_______________________________________________________________________ +function _deluid(p) +{ + ################################################# 1 # + if (p in _CLASSPTR) { + _deluida0 = _CLASSPTR[p] + if (_deluida0 in _UIDOBL) { + _UIDOBLV[_UIDOBL[_deluida0]][p] + } + } + delete _CLASSPTR[p] + return _deluida0 +} + +#_______________________________________________________________________ +function _dir(A, rd, i, r, f, ds, pf, B, C) +{ + #################################### + delete A + gsub(/(^[ \t]*)|([ \t]*$)/, "", rd) + if (rd == "") { + return "" } - - function _dirtree_i0(B, i, c, A, f, lf, a, C) - { - delete A[f] - A[f][0] - delete A[f][0] - lf = length(f) - for (; i <= c; ) { - if (match(B[i], /^[ \t]*Directory of (.+)/, C)) { - if (substr(a = _filerd(C[1] "\\"), 1, lf) == f) { - i = _dirtree_i0(B, i + 4, c, A[f], a) + i = split(_cmd("dir \"" rd "\" 2>NUL"), B, /\x0D?\x0A/) - 3 + pf = (match(B[4], /Directory of ([^\x00-\x1F]+)/, C) ? C[1] ((C[1] ~ /\\$/ ? "" : "\\")) : "") + for (r = 0; i > 5; i--) { + if (match(B[i], /^([^ \t]*)[ \t]+([^ \t]*)[ \t]+((<DIR>)|([0-9\,]+))[ \t]+([^\x00-\x1F]+)$/, C)) { + if (C[6] !~ /^\.\.?$/) { + if (C[4]) { + ds = "D " } else { - return i + ds = C[5] " " + gsub(/\,/, "", ds) } - } else { - if (match(B[i++], /^([^ \t\-]+)\-([^ \t\-]+)\-([^ \t]+)[ \t]+([^ \t]+)[ \t]+([0-9]+)[ \t]+(.+)$/, C)) { - A[f][f C[6]] = C[5] " " C[1] "/" _CHR["MONTH"][C[2]] "/" C[3] " " C[4] + if ((f = _filepath(pf C[6] ((C[4] ? "\\" : "")))) != "") { + A[f] = ds C[1] " " C[2] + r++ } } } - return i } - - function _dll_check(pp) - { - _dllchktv = "" - _missfl = 1 - _tframe("_dll_check_i0", pp, _REG, pp) - if (1 || "AGENT" in _[pp]) { - if (_dllchktv != _[pp][".Product Version"]) { - _dllerr(_[pp]["AGENT"], "agent version (" _[pp][".Product Version"] ") do not match all lib versions: " _dllchktv "'") + return r +} + +#_________________________________________________________________ +function _dirtree(A, f, B) +{ + ######################################### + gsub(/(^[ \t]*)|([ \t]*$)/, "", f) + delete A + A[""] + delete A[""] + _dirtree_i0(B, 8, split(_cmd("dir \"" f "\" /-C /S 2>NUL"), B, /\x0D?\x0A/), A, f = _filerd(f)) + return f +} + +#___________________________________________________________ +function _dirtree_i0(B, i, c, A, f, lf, a, C) +{ + delete A[f] + A[f][0] + delete A[f][0] + lf = length(f) + for (; i <= c; ) { + if (match(B[i], /^[ \t]*Directory of (.+)/, C)) { + if (substr(a = _filerd(C[1] "\\"), 1, lf) == f) { + i = _dirtree_i0(B, i + 4, c, A[f], a) + } else { + return i } } else { - if (! _missfl) { - _creport(pp, "agent not detected in registry") - } else { - _dllerr(pp, "agent not detected in registry but some registry entries exist:") - _tframe("_dll_check_i1", pp, pp) + if (match(B[i++], /^([^ \t\-]+)\-([^ \t\-]+)\-([^ \t]+)[ \t]+([^ \t]+)[ \t]+([0-9]+)[ \t]+(.+)$/, C)) { + A[f][f C[6]] = C[5] " " C[1] "/" _CHR["MONTH"][C[2]] "/" C[3] " " C[4] } } } + return i +} - function _dll_check_i0(p, R, pp, p2, i, i2, r, f, v, rs, d, tv, tf) - { - if (_[p]["TYPE"] == "defdll") { - r = toupper(_[p]["REGPATH"]) - rs = 0 - tf = 0 - tv = "" - for (i in R) { - if (toupper(substr(i, 1, length(r))) == r) { - if ((_chka0 = substr(i, 1 + length(r), 1)) == "" || _chka0 == "\\") { +#_______________________________________________________________________ +function _dll_check(pp) +{ + _dllchktv = "" + _missfl = 1 + _tframe("_dll_check_i0", pp, _REG, pp) + #also check that all dll have same version; also check that all dlls have success and then report that DS plug-in version n - installed + if (1 || "AGENT" in _[pp]) { + if (_dllchktv != _[pp][".Product Version"]) { + _dllerr(_[pp]["AGENT"], "agent version (" _[pp][".Product Version"] ") do not match all lib versions: " _dllchktv "'") + } + } else { + if (! _missfl) { + _creport(pp, "agent not detected in registry") + } else { + _dllerr(pp, "agent not detected in registry but some registry entries exist:") + _tframe("_dll_check_i1", pp, pp) + } + } +} + +#_______________________________________________ +function _dll_check_i0(p, R, pp, p2, i, i2, r, f, v, rs, d, tv, tf) +{ + if (_[p]["TYPE"] == "defdll") { + r = toupper(_[p]["REGPATH"]) + rs = 0 + tf = 0 + tv = "" + for (i in R) { + if (toupper(substr(i, 1, length(r))) == r) { + if ((_chka0 = substr(i, 1 + length(r), 1)) == "" || _chka0 == "\\") { + rs = 1 + _missfl = 1 + _[p]["." substr(gensub(/\....$/, "", 1, i), i2 = 2 + length(r), length(i) - i2 + 1)] = R[i] + if (chka0 != "") { rs = 1 - _missfl = 1 - _[p]["." substr(gensub(/\....$/, "", 1, i), i2 = 2 + length(r), length(i) - i2 + 1)] = R[i] - if (chka0 != "") { - rs = 1 - } } } } - if (rs) { - if ((i = ".Install Path") in _[p] && (i = ".Product Version") in _[p]) { - _[p]["STATUS"] = "PRESENT" - f = _[p][".Install Path"] - v = _[p][".Product Version"] - if (! (".Module" in _[p])) { - _[pp][".Product Version"] = v - _VAR["HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR"] = f - _[pp]["AGENT"] = p - _creport("OK: DLL DETECTED(" v "): " substr(_[p]["NAME"], 1, 112)) + } + #{ rs=_missfl=1; _[p]["." gensub(/^([^\\]+\\)+(.*)\..../,"\\2","G",i)]=R[i] } } + if (rs) { + if ((i = ".Install Path") in _[p] && (i = ".Product Version") in _[p]) { + _[p]["STATUS"] = "PRESENT" + f = _[p][".Install Path"] + v = _[p][".Product Version"] + if (! (".Module" in _[p])) { + _[pp][".Product Version"] = v + _VAR["HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR"] = f + _[pp]["AGENT"] = p + _creport("OK: DLL DETECTED(" v "): " substr(_[p]["NAME"], 1, 112)) + } else { + if (_dllchktv == "") { + _dllchktv = v } else { - if (_dllchktv == "") { - _dllchktv = v - } else { - if (v != _dllchktv) { - return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'") - } - } - ERRNO = "" - if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { - delete _[p]["DATA"] - return _dllerr(p, "read lib: " ERRNO, f) - } - if (v != (_[p]["VERSION"] = _getfilever(f))) { - return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + if (v != _dllchktv) { + return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'") } - _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100)) } - } else { - tf = 1 - _dllerr(p, "registry corrupt: `" i "' not present") + ERRNO = "" + if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { + delete _[p]["DATA"] + return _dllerr(p, "read lib: " ERRNO, f) + } + if (v != (_[p]["VERSION"] = _getfilever(f))) { + return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + } + _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100)) } } else { - _[p]["STATUS"] = "MISSED" + tf = 1 + _dllerr(p, "registry corrupt: `" i "' not present") } + } else { + _[p]["STATUS"] = "MISSED" } } +} - function _dll_check_i1(p, pp, p1, p2, p3, i) - { - if (_[p]["TYPE"] == "defdll") { - for (i in _[p]) { - if (i ~ /^\./) { - _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2)) - } +#_______________________________________________ +function _dll_check_i1(p, pp, p1, p2, p3, i) +{ + if (_[p]["TYPE"] == "defdll") { + for (i in _[p]) { + if (i ~ /^\./) { + _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2)) } } } +} - function _dllerr(p, t, f) - { - if (t !~ /\x00/) { - t = "ERROR: \000" t - } - _errfl = 1 - _[p]["ERROR"] = _[p]["ERROR"] _ln(t ((f == "" ? "" : ": " f))) +#___________________________________________________________________________________ +function _dllerr(p, t, f) +{ + if (t !~ /\x00/) { + t = "ERROR: \000" t } + _errfl = 1 + _[p]["ERROR"] = _[p]["ERROR"] _ln(t ((f == "" ? "" : ": " f))) +} - function _drawuid(p, cn, ch, o) - { - _conl("uid: " p) - _conl("\toblptr: " ((p in _UIDOBL ? _UIDOBL[p] "'" : "-"))) - if (p in _UIDOBL) { - if (! _isptr(o = _UIDOBL[p])) { - _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer") - } - if (! isarray(_UIDOBLV[o])) { - _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr") - } +function _drawuid(p, cn, ch, o) +{ + _conl("uid: " p) + _conl("\toblptr: " ((p in _UIDOBL ? _UIDOBL[p] "'" : "-"))) + if (p in _UIDOBL) { + if (! _isptr(o = _UIDOBL[p])) { + _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer") } - _conl("\tprefix: " ((p in _UIDPFX ? _UIDPFX[p] "'" : "-"))) - _conl("\tsuffix: " ((p in _UIDSFX ? _UIDSFX[p] "'" : "-"))) - _conl("\tcounters: " (cn = (p in _UIDCNT ? _UIDCNT[p] "'" : "-"))) - if (cn != "-") { - _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'") - _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'") - } - _conl("\tcharset: " (ch = (p in _UIDCHR ? _UIDCHR[p] "'" : "-"))) - if (ch != "-") { - _conl("chrH: ") - _conl(_dumparr(_UIDCHRH[_UIDCHR[p]])) - _conl() - _conl("chrL: ") - _conl(_dumparr(_UIDCHRL[_UIDCHR[p]])) - _conl() - } - } - - function _dumparr(A, t, lv, a) - { - b = PROCINFO["sorted_in"] - PROCINFO["sorted_in"] = "_lengthsort" - if (isarray(A)) { - delete _DUMPARR - _dumparrc = _dumparrd = "" - _dumparr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) - PROCINFO["sorted_in"] = a - return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") - } - } - - function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f) - { - t2 = _getchrln(" ", length(t)) - if (ln == lv) { - if (ls > 0) { - for (i in A) { - ++a - } - } else { - for (i in A) { - (isarray(A[i]) ? ++a : "") - } - } - if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" - } - return + if (! isarray(_UIDOBLV[o])) { + _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr") } - if (ls >= 0) { + } + _conl("\tprefix: " ((p in _UIDPFX ? _UIDPFX[p] "'" : "-"))) + _conl("\tsuffix: " ((p in _UIDSFX ? _UIDSFX[p] "'" : "-"))) + _conl("\tcounters: " (cn = (p in _UIDCNT ? _UIDCNT[p] "'" : "-"))) + if (cn != "-") { + _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'") + _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'") + } + _conl("\tcharset: " (ch = (p in _UIDCHR ? _UIDCHR[p] "'" : "-"))) + if (ch != "-") { + _conl("chrH: ") + _conl(_dumparr(_UIDCHRH[_UIDCHR[p]])) + _conl() + _conl("chrL: ") + _conl(_dumparr(_UIDCHRL[_UIDCHR[p]])) + _conl() + } +} + +#_______________________________________________________________________ +function _dumparr(A, t, lv, a) +{ + ############################################ + b = PROCINFO["sorted_in"] + PROCINFO["sorted_in"] = "_lengthsort" + if (isarray(A)) { + delete _DUMPARR + _dumparrc = _dumparrd = "" + _dumparr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) + PROCINFO["sorted_in"] = a + return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") + } +} + +#___________________________________________________________ +function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f) +{ + t2 = _getchrln(" ", length(t)) + if (ln == lv) { + if (ls > 0) { for (i in A) { - if (! isarray(A[i])) { - if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" - } - } + ++a } - } - for (i in A) { - if (isarray(A[i])) { - _dumparr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") + } else { + for (i in A) { + (isarray(A[i]) ? ++a : "") } } - if (! f) { - if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" - } + if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" } + return } - - function _dumpobj(p, f, t, s) - { - s = _dumpobj_i0(p, f, t = t "." p "{") - if (p = _rFCHLD(p)) { - return (s = s _dumpobjm(p, f, (s ? _getchrln(" ", length(t) - 1) : t " "))) + if (ls >= 0) { + for (i in A) { + if (! isarray(A[i])) { + if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" + } + } } - return s } - - function _dumpobj_i0(p, f, t) - { - if (f == "") { - return _dumpobj_i2(p, t) + for (i in A) { + if (isarray(A[i])) { + _dumparr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") } - if (f == 0) { - return _dumpobj_i1(p, t " ") + } + if (! f) { + if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" } - return (_dumpobj_i1(p, t " ") _dumpobj_i2(p, _getchrln(" ", length(t)))) } +} - function _dumpobj_i1(p, t) - { - return _ln(t substr(((p in _tPREV ? "\253" _tPREV[p] : "")) " ", 1, 7) " " substr(((p in _tPARENT ? "\210" _tPARENT[p] : "")) " ", 1, 7) " " substr(((p in _tFCHLD ? _tFCHLD[p] : "")) "\205" ((p in _tQCHLD ? " (" _tQCHLD[p] ") " : "\205")) "\205" ((p in _tLCHLD ? _tLCHLD[p] : "")) " ", 1, 22) substr(((p in _tNEXT ? "\273" _tNEXT[p] : "")) " ", 1, 8)) +#___________________________________________________________________________________ +#################################################################################### + + +#___________________________________________________________________________________ +# OTHER tFUNCTIONs ################################################################# + +#_____________________________________________________________________________ +function _dumpobj(p, f, t, s) +{ + ################################################### + s = _dumpobj_i0(p, f, t = t "." p "{") + if (p = _rFCHLD(p)) { + return (s = s _dumpobjm(p, f, (s ? _getchrln(" ", length(t) - 1) : t " "))) } + return s +} - function _dumpobj_i2(p, t) - { - return (_dumpobj_i3(_[p], t " ") _dumpobj_i3(_ptr[p], _getchrln(" ", length(t)) "`", "`")) +#___________________________________________________________ +function _dumpobj_i0(p, f, t) +{ + if (f == "") { + return _dumpobj_i2(p, t) } + if (f == 0) { + return _dumpobj_i1(p, t " ") + } + return (_dumpobj_i1(p, t " ") _dumpobj_i2(p, _getchrln(" ", length(t)))) +} + +#___________________________________________________________ +function _dumpobj_i1(p, t) +{ + return _ln(t substr(((p in _tPREV ? "\253" _tPREV[p] : "")) " ", 1, 7) " " substr(((p in _tPARENT ? "\210" _tPARENT[p] : "")) " ", 1, 7) " " substr(((p in _tFCHLD ? _tFCHLD[p] : "")) "\205" ((p in _tQCHLD ? " (" _tQCHLD[p] ") " : "\205")) "\205" ((p in _tLCHLD ? _tLCHLD[p] : "")) " ", 1, 22) substr(((p in _tNEXT ? "\273" _tNEXT[p] : "")) " ", 1, 8)) +} - function _dumpobj_i3(A, t, p, e, s, i, t2) - { - if (isarray(A)) { +#___________________________________________________________ +function _dumpobj_i2(p, t) +{ + return (_dumpobj_i3(_[p], t " ") _dumpobj_i3(_ptr[p], _getchrln(" ", length(t)) "`", "`")) +} + +#___________________________________________________________ +function _dumpobj_i3(A, t, p, e, s, i, t2) +{ + if (isarray(A)) { + for (i in A) { + t2 = _getchrln(" ", length(t)) for (i in A) { - t2 = _getchrln(" ", length(t)) - for (i in A) { - if (isarray(A[i])) { - s = s _dumpobj_i3(A[i], t "[" _dumpobj_i4(i) "]", p, _ln()) - } else { - s = s _ln(t "[" _dumpobj_i4(i) "]=" p _dumpobj_i4(A[i]) "'") - } - t = t2 + if (isarray(A[i])) { + s = s _dumpobj_i3(A[i], t "[" _dumpobj_i4(i) "]", p, _ln()) + } else { + s = s _ln(t "[" _dumpobj_i4(i) "]=" p _dumpobj_i4(A[i]) "'") } - return s + t = t2 } - return ((e == "" ? "" : t e)) + return s } - if (A == 0 && A == "") { - return - } - return _ln(t "=" _dumpobj_i4(p A) "'") + return ((e == "" ? "" : t e)) } - - function _dumpobj_i4(t) - { - if (length(t) > 64) { - return (substr(t, 1, 28) " ... " substr(t, length(t) - 28)) - } - return t - } - - function _dumpobj_nc(p, f, t) - { - return _dumpobj_i0(p, f, t "." p "{ ") + if (A == 0 && A == "") { + return } - - function _dumpobjm(p, f, t, s, t2) - { - t2 = _getchrln(" ", length(t)) - do { - s = s _dumpobj(p, f, t) - t = t2 - } while (p = _rNEXT(p)) - return s + return _ln(t "=" _dumpobj_i4(p A) "'") +} + +#___________________________________________________________ +function _dumpobj_i4(t) +{ + if (length(t) > 64) { + return (substr(t, 1, 28) " ... " substr(t, length(t) - 28)) + } + return t +} + +#_________________________________________________________________ +function _dumpobj_nc(p, f, t) +{ + ####################################### + return _dumpobj_i0(p, f, t "." p "{ ") +} + +#_________________________________________________________________ +function _dumpobjm(p, f, t, s, t2) +{ + ################################### + t2 = _getchrln(" ", length(t)) + do { + s = s _dumpobj(p, f, t) + t = t2 + } while (p = _rNEXT(p)) + return s +} + +#_________________________________________________________________ +function _dumpobjm_nc(p, f, t, s, t2) +{ + ################################ + t2 = _getchrln(" ", length(t)) + do { + s = s _dumpobj_nc(p, f, t) + t = t2 + } while (p = _rNEXT(p)) + return s +} + +function _dumpuidgen(p, pd, pc, ps) +{ + _conline("#" ++cntdm ": " p "'") + _conl() + if (p in _tuidel) { + _conl("DEL: " _var(pd = _tuidel[p])) + _conl(_dumparr(_tUIDEL[pd]) _ln()) + } + _conl("PFX: " _tUIDPFX[p] "'") + _conl("SFX: " _tUIDSFX[p] "'") + _conl("COUNT: " ((p in _tuidcnt ? (pc = _tuidcnt[p]) "'" : _th0("-", pc = -2)))) + _con("CHARS: ") + if (p in _tuidchr) { + _conl((ps = _tuidchr[p]) "'") + _conl("HCHR: " ((pc == -2 ? "-" : _tUIDCNTH[pc] "'"))) + _conl(_dumparr(_tUIDCHRH[ps]) _ln()) + _conl("LCHR: " ((pc == -2 ? "-" : _tUIDCNTL[pc] "'"))) + _conl(_dumparr(_tUIDCHRL[ps]) _ln()) + } else { + _conl("-") + } +} + +#_____________________________________________________________________________ +function _dumpval(v, n) +{ + _dumpstr = _dumpstr (v = _ln(((n == 0 && n == "" ? "RET" : n)) ": " ((v == 0 && v == "" ? "-" : v "'")))) + return v +} + +######################################################## + +function _eXTFN(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_extfn 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } - - function _dumpobjm_nc(p, f, t, s, t2) - { - t2 = _getchrln(" ", length(t)) - do { - s = s _dumpobj_nc(p, f, t) - t = t2 - } while (p = _rNEXT(p)) - return s +} + +#_________________________________________________________________ +function _endpass(t) +{ + _endpass_v0 = t +} + +#_______________________________________________________________________ +function _err(t, a, b) +{ + ################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > _SYS_STDERR + fflush(_SYS_STDERR) + BINMODE = a + ORS = b + return t +} + +#_________________________________________________________________ +function _errnl(t) +{ + ################################################ + return _err(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) +} + +#_______________________________________________________________________ +function _error(t, d, A) +{ + ################################################# + if (_ERRLOG_EF) { + A["TYPE"] = "ERROR" + A["TEXT"] = t + _log(A, d) + } +} + +#_______________________________________________________________________ +function _exit(c) +{ + ####################################################### + exit c +} + +#_____________________________________________________________________________ +function _export_data(t, i, A) +{ + ################################################# + A["DATA"] = t + A["ID"] = i + _expout("_DATA: " _Zexparr(A) "\n") +} + +#___________________________________________________________________________________ +#################################################################################### + +#_____________________________________________________________________________ +function _expout(t, d, a, b) +{ + #################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > ((d ? d : d = _errlog_file)) + fflush(d) + BINMODE = a + ORS = b +} + +#_________________________________________________________________________________________ +########################################################################################## + + + + + + + + +function _extfn_init() +{ + ############################################################## + + _formatstrs_init() + _formatstrd_init() + _formatrexp_init() + _unformatstr_init() + _mac_init() +} + +function _faccl_i0(A, t, p, P, f, r) +{ + f = r = "" + if (isarray(A)) { + while (f = A[f]) { + r = (@f(t, p, P)) r + } + } + return r +} + +function _faccr_i0(A, t, p, P, f, r) +{ + f = r = "" + if (isarray(A)) { + while (f = A[f]) { + r = r @f(t, p, P) + } + } + return r +} + +#_______________________________________________________________________ +function _fatal(t, d, A) +{ + ################################################# + if (_ERRLOG_FF) { + A["TYPE"] = "FATAL" + A["TEXT"] = t + _log(A, d) + } + if (! d) { + exit + } +} + +function _fbaccl(A, t, p, P) +{ + return _faccl_i0(A["B"], t, p, P) +} + +function _fbaccr(A, t, p, P) +{ + return _faccr_i0(A["B"], t, p, P) +} + +function _ffaccl(A, t, p, P) +{ + return _faccl_i0(A["F"], t, p, P) +} + +function _ffaccr(A, t, p, P) +{ + return _faccr_i0(A["F"], t, p, P) +} + +################## +#_______________________________________________________________________ +function _fframe(A, t, p) +{ + ################################################# + return _fframe_i0(A, t, p, A[""]) +} + +#___________________________________________________________ +function _fframe_i0(A, t, p, f) +{ + return ((f ? (@f(t, p)) _fframe_i0(A, t, p, A[f]) : "")) +} + +#_________________________________________________________________ +function _file(f) +{ + ################################################# + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _dumpuidgen(p, pd, pc, ps) - { - _conline("#" ++cntdm ": " p "'") - _conl() - if (p in _tuidel) { - _conl("DEL: " _var(pd = _tuidel[p])) - _conl(_dumparr(_tUIDEL[pd]) _ln()) - } - _conl("PFX: " _tUIDPFX[p] "'") - _conl("SFX: " _tUIDSFX[p] "'") - _conl("COUNT: " ((p in _tuidcnt ? (pc = _tuidcnt[p]) "'" : _th0("-", pc = -2)))) - _con("CHARS: ") - if (p in _tuidchr) { - _conl((ps = _tuidchr[p]) "'") - _conl("HCHR: " ((pc == -2 ? "-" : _tUIDCNTH[pc] "'"))) - _conl(_dumparr(_tUIDCHRH[ps]) _ln()) - _conl("LCHR: " ((pc == -2 ? "-" : _tUIDCNTL[pc] "'"))) - _conl(_dumparr(_tUIDCHRL[ps]) _ln()) + return ((f in _FILEXT ? _FILEXT[f] : "")) +} + +#_______________________________________________________________________ +function _file_check(p) +{ + if (1 || "AGENT" in _[p]) { + _tframe("_file_check_i0", p, p) + } +} + +#_______________________________________________ +function _file_check_i0(p, pp, p1, p2, f, v) +{ + if (_[p]["TYPE"] == "defile") { + f = _[p]["FILE"] + f = ((match(f, /^.:/) ? "" : _[_[pp]["AGENT"]][".Install Path"] "\\")) _[p]["FILE"] + if ("RQVERSION" in _[p]) { + v = _[p]["RQVERSION"] } else { - _conl("-") + v = _[pp][".Product Version"] } - } - - function _dumpval(v, n) - { - _dumpstr = _dumpstr (v = _ln(((n == 0 && n == "" ? "RET" : n)) ": " ((v == 0 && v == "" ? "-" : v "'")))) - return v - } - - function _eXTFN(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_extfn 1.0") - case "_lib_BEGIN": - return - case "_lib_END": - return + ERRNO = "" + if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { + delete _[p]["DATA"] + return _dllerr(p, "read file: " ERRNO, f) + } + if (v != "" && v != (_[p]["VERSION"] = _getfilever(f))) { + return _dllerr(p, " file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + } + _creport(p, substr("OK: FILE DETECTED" ((v == "" ? "" : "(" v ")")) ": " f, 1, 122)) + } else { + if (_[p]["TYPE"] == "defdir") { + if (_filexist(f = _[p]["DIR"])) { + _creport(p, substr("OK: DIR DETECTED: " f, 1, 112)) + } else { + _dllerr(p, "directory " f " is not detected") + } } } +} - function _endpass(t) - { - _endpass_v0 = t - } - - function _err(t, a, b) - { - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > _SYS_STDERR - fflush(_SYS_STDERR) - BINMODE = a - ORS = b - return t +#_________________________________________________________________ +function _filed(f, dd, d) +{ + ########################################## + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _errnl(t) - { - return _err(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) + if (f in _FILEDIRFL) { + return _FILEDIR[f] } - - function _error(t, d, A) - { - if (_ERRLOG_EF) { - A["TYPE"] = "ERROR" - A["TEXT"] = t - _log(A, d) + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] } + return (_FILEDIR[f] = d _FILEDIR[f]) } - - function _exit(c) - { - exit c + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEDIR) { + return _FILEDIR[dd, f] } - - function _export_data(t, i, A) - { - A["DATA"] = t - A["ID"] = i - _expout("_DATA: " _Zexparr(A) "\n") + if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { + return (_FILEDIR[dd, f] = d) } + return d +} - function _expout(t, d, a, b) - { - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > ((d ? d : d = _errlog_file)) - fflush(d) - BINMODE = a - ORS = b +#_________________________________________________________________ +function _filen(f) +{ + ################################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return ((f in _FILENAM ? _FILENAM[f] : "")) +} - function _extfn_init() - { - _formatstrs_init() - _formatstrd_init() - _formatrexp_init() - _unformatstr_init() - _mac_init() +#_________________________________________________________________ +function _filene(f) +{ + ############################################### + if ((f = _filerdnehnd(f)) == "") { + return "" } + return (((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) +} - function _faccl_i0(A, t, p, P, f, r) - { - f = r = "" - if (isarray(A)) { - while (f = A[f]) { - r = (@f(t, p, P)) r - } - } - return r +#_________________________________________________________________ +function _filenotexist(f, a) +{ + ###################################### + if (f == "") { + return "" } - - function _faccr_i0(A, t, p, P, f, r) - { - f = r = "" - if (isarray(A)) { - while (f = A[f]) { - r = r @f(t, p, P) - } - } - return r + if ((a = _filepath(f)) == "") { + ERRNO = "Filepath error `" f "'" + return "" } - - function _fatal(t, d, A) - { - if (_ERRLOG_FF) { - A["TYPE"] = "FATAL" - A["TEXT"] = t - _log(A, d) - } - if (! d) { - exit - } + _cmd("if exist \"" a "\" exit 1 2>NUL") + if (_exitcode == 1) { + return (ERRNO = _NOP) } + return a +} - function _fbaccl(A, t, p, P) - { - return _faccl_i0(A["B"], t, p, P) +#_______________________________________________________________________ +function _filepath(f, dd) +{ + ################################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return (filegetrootdir(f, dd) ((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) +} - function _fbaccr(A, t, p, P) - { - return _faccr_i0(A["B"], t, p, P) +#_________________________________________________________________ +function _filer(f, dd) +{ + ############################################# + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _ffaccl(A, t, p, P) - { - return _faccl_i0(A["F"], t, p, P) + if (f in _FILEROOT) { + return _FILEROOT[f] } - - function _ffaccr(A, t, p, P) - { - return _faccr_i0(A["F"], t, p, P) + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { + return _FILEROOT[dd, f] } + return (_FILEROOT[dd, f] = fileri(dd)) +} - function _fframe(A, t, p) - { - return _fframe_i0(A, t, p, A[""]) +#_________________________________________________________________ +function _filerd(f, dd) +{ + ############################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return filegetrootdir(f, dd) +} - function _fframe_i0(A, t, p, f) - { - return ((f ? (@f(t, p)) _fframe_i0(A, t, p, A[f]) : "")) +#_________________________________________________________________ +function _filerdn(f, dd) +{ + ########################################### + if ((f = _filerdnehnd(f)) == "") { + return "" } + return ((f in _FILENAM ? filegetrootdir(f, dd) _FILENAM[f] : "")) +} - function _file(f) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILEXT ? _FILEXT[f] : "")) +#_________________________________________________________________ +function _filerdne(f, dd) +{ + ########################################## + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _file_check(p) - { - if (1 || "AGENT" in _[p]) { - _tframe("_file_check_i0", p, p) - } + if (f in _FILENAM) { + return (filegetrootdir(f, dd) _FILENAM[f] ((f in _FILEXT ? _FILEXT[f] : ""))) + } + if (f in _FILEXT) { + return (filegetrootdir(f, dd) _FILEXT[f]) } + return "" +} - function _file_check_i0(p, pp, p1, p2, f, v) - { - if (_[p]["TYPE"] == "defile") { - f = _[p]["FILE"] - f = ((match(f, /^.:/) ? "" : _[_[pp]["AGENT"]][".Install Path"] "\\")) _[p]["FILE"] - if ("RQVERSION" in _[p]) { - v = _[p]["RQVERSION"] +#___________________________________________________________ +function _filerdnehnd(st, c, r, d, n, A) +{ + if (st) { + if ((c = toupper(st)) in _FILECACHE) { + FLENGTH = length(st) + return _FILECACHE[c] + } + if (match(st, /^[ \t]*\\[ \t]*\\/)) { + if (match(substr(st, (FLENGTH = RLENGTH) + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { + FLENGTH = FLENGTH + RLENGTH + d = ((A[3] ? "\\" A[3] "$" : "")) A[4] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) + } + _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + _FILEDIRFL[c] + _FILEROOT[c] = r } else { - v = _[pp][".Product Version"] + FLENGTH = 0 + _filepath_err = "UNC" + return "" + } + } else { + match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) + if (! (FLENGTH = RLENGTH)) { + return "" } - ERRNO = "" - if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { - delete _[p]["DATA"] - return _dllerr(p, "read file: " ERRNO, f) + d = A[8] A[10] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) } - if (v != "" && v != (_[p]["VERSION"] = _getfilever(f))) { - return _dllerr(p, " file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + if (A[8]) { + _FILEDIRFL[c] } - _creport(p, substr("OK: FILE DETECTED" ((v == "" ? "" : "(" v ")")) ": " f, 1, 122)) - } else { - if (_[p]["TYPE"] == "defdir") { - if (_filexist(f = _[p]["DIR"])) { - _creport(p, substr("OK: DIR DETECTED: " f, 1, 112)) - } else { - _dllerr(p, "directory " f " is not detected") - } + if (r) { + _FILEROOT[c] = r } } - } - - function _filed(f, dd, d) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILEDIRFL) { - return _FILEDIR[f] - } - if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] + if (n) { + if (match(n, /\.[^\.]*$/)) { + _FILEXT[c] = substr(n, RSTART) + _FILENAM[c] = substr(n, 1, RSTART - 1) + } else { + _FILENAM[c] = n } - return (_FILEDIR[f] = d _FILEDIR[f]) - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEDIR) { - return _FILEDIR[dd, f] - } - if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return (_FILEDIR[dd, f] = d) } - return d + return c } + return "" +} - function _filen(f) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILENAM ? _FILENAM[f] : "")) +#_______________________________________________________________________ +function _filexist(f, a) +{ + ################################################ + if (f == "") { + return "" } - - function _filene(f) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return (((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) + if ((a = _filepath(f)) == "") { + ERRNO = "Filepath error `" f "'" + return "" } - - function _filenotexist(f, a) - { - if (f == "") { - return "" - } - if ((a = _filepath(f)) == "") { - ERRNO = "Filepath error `" f "'" - return "" - } - _cmd("if exist \"" a "\" exit 1 2>NUL") - if (_exitcode == 1) { - return (ERRNO = _NOP) - } + _cmd("if exist \"" a "\" exit 1 2>NUL") + if (_exitcode == 1) { return a } - - function _filepath(f, dd) - { - if ((f = _filerdnehnd(f)) == "") { - return "" + ERRNO = "File not found `" f "'" + return _NOP +} + +#_______________________________________________________________________ +function _fn(f, p0, p1, p2) +{ + ################################################ + if (f in FUNCTAB) { + return @f(p0, p1, p2) + } +} + +#_______________________________________________________________________ +function _foreach(A, f, r, p0, p1, p2, i, p) +{ + #################################### + if (isarray(A)) { + _TMP0[p = _n()]["."] = 1 + _foreach_i0(A, f, _TMP0[p], p0, p1, p2) + return _th0(_retarr(_TMP0[p]), _tdel(p)) + } + if (_isptr(A)) { + _TMP0[p = _n()][_ARRLEN] = 1 + _tframe4("_foreach_i1" ((r ? "~" r : "")), A, f, _TMP0[p], p0, p1) + return _th0(_retarr(_TMP0[p]), _tdel(p)) + } +} + +#_____________________________________________________ +function _foreach_i0(A, f, D, p0, p1, p2) +{ + for (i in A) { + if (isarray(A[i])) { + _foreach_i0(A[i], f, D, p0, p1, p2) + } else { + _gen(D, @f(A[i], p0, p1, p2)) } - return (filegetrootdir(f, dd) ((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) } +} - function _filer(f, dd) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILEROOT) { - return _FILEROOT[f] - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - return _FILEROOT[dd, f] - } - return (_FILEROOT[dd, f] = fileri(dd)) - } +#_____________________________________________________ +function _foreach_i1(p, f, D, p0, p1, p2) +{ + _gen(D, @f(p, p0, p1, p2)) +} - function _filerd(f, dd) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return filegetrootdir(f, dd) +#_____________________________________________________________________________ +function _formatrexp(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /[\/\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATREXPESC[_FORMATSTRB[t]] } + return (_formatstrs0 _FORMATSTRA[t]) +} - function _filerdn(f, dd) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILENAM ? filegetrootdir(f, dd) _FILENAM[f] : "")) - } +#___________________________________________________________ +function _formatrexp_init() +{ + _defescarr(_FORMATREXPESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATREXPESC, "\\/", "\\") + _FORMATREXPESC["\t"] = "\\t" +} - function _filerdne(f, dd) - { - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILENAM) { - return (filegetrootdir(f, dd) _FILENAM[f] ((f in _FILEXT ? _FILEXT[f] : ""))) - } - if (f in _FILEXT) { - return (filegetrootdir(f, dd) _FILEXT[f]) - } - return "" +#_____________________________________________________________________________ +function _formatstrd(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /["\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRDESC[_FORMATSTRB[t]] } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _formatstrd_init() +{ + _defescarr(_FORMATSTRDESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATSTRDESC, "[\\\\\"]", "\\") + _FORMATSTRDESC["\t"] = "\\t" +} + +#__________________________________________________________________________________ +#################################################################################### + - function _filerdnehnd(st, c, r, d, n, A) - { - if (st) { - if ((c = toupper(st)) in _FILECACHE) { - FLENGTH = length(st) - return _FILECACHE[c] - } - if (match(st, /^[ \t]*\\[ \t]*\\/)) { - if (match(substr(st, (FLENGTH = RLENGTH) + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { - FLENGTH = FLENGTH + RLENGTH - d = ((A[3] ? "\\" A[3] "$" : "")) A[4] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - _FILEDIRFL[c] - _FILEROOT[c] = r - } else { - FLENGTH = 0 - _filepath_err = "UNC" - return "" - } - } else { - match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) - if (! (FLENGTH = RLENGTH)) { - return "" - } - d = A[8] A[10] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - if (A[8]) { - _FILEDIRFL[c] - } - if (r) { - _FILEROOT[c] = r - } - } - if (n) { - if (match(n, /\.[^\.]*$/)) { - _FILEXT[c] = substr(n, RSTART) - _FILENAM[c] = substr(n, 1, RSTART - 1) - } else { - _FILENAM[c] = n - } - } - return c - } - return "" - } - function _filexist(f, a) - { - if (f == "") { - return "" - } - if ((a = _filepath(f)) == "") { - ERRNO = "Filepath error `" f "'" - return "" - } - _cmd("if exist \"" a "\" exit 1 2>NUL") - if (_exitcode == 1) { - return a - } - ERRNO = "File not found `" f "'" - return _NOP - } - function _fn(f, p0, p1, p2) - { - if (f in FUNCTAB) { - return @f(p0, p1, p2) - } +#___________________________________________________________________________________ +function _formatstrs(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRSESC[_FORMATSTRB[t]] } - - function _foreach(A, f, r, p0, p1, p2, i, p) - { - if (isarray(A)) { - _TMP0[p = _n()]["."] = 1 - _foreach_i0(A, f, _TMP0[p], p0, p1, p2) - return _th0(_retarr(_TMP0[p]), _tdel(p)) - } - if (_isptr(A)) { - _TMP0[p = _n()][_ARRLEN] = 1 - _tframe4("_foreach_i1" ((r ? "~" r : "")), A, f, _TMP0[p], p0, p1) - return _th0(_retarr(_TMP0[p]), _tdel(p)) + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _formatstrs_init() +{ + _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATSTRSESC, "[\\\\']", "\\") + _FORMATSTRSESC["\t"] = "\\t" +} + +function _fpp(q, D, S) +{ + _conl() + _conline(q) + _conl() + q = _patharr0(S, q) + #_arregpath(D,S) + #_conl(_dumparr(D)) + _conl(_dumparr(S)) + _conl() + return q +} + +#_______________________________________________________________________ +######################################################################## + + + + + + + + + +function _fthru(A, c, p, B) +{ + return _fthru_i0(A, c, p, B, A[""]) +} + +#_________________________________________________________________ +function _fthru_i0(A, c, p, B, f) +{ + return ((f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : "")) +} + +function _gen(D, t) +{ + if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) { + D[++D[_ARRLEN]] = "" + } +} + +#_____________________________________________________________________________ +function _gensubfn(t, r, f, p0, A) +{ + ############################################### + if (match(t, r, A)) { + return (substr(t, 1, RSTART - 1) (@f(_th0(substr(t, RSTART, RLENGTH), t = substr(t, RSTART + RLENGTH)), A, p0)) _gensubfn(t, r, f, p0)) + } + return t +} + +#_____________________________________________________________________________ +function _get_errout(p) +{ + ####################################################### + return _tframe("_get_errout_i0", p) +} + +#_______________________________________________________________________ +function _get_errout_i0(p, t, n, a) +{ + return ((p in _tLOG ? _get_errout_i1(p) _get_errout_i3(p) : "")) +} + +#_________________________________________________________________ +function _get_errout_i1(p, t, n, a) +{ + if (p in _tLOG) { + n = "" + if (_tLOG[p]["TYPE"]) { + n = _tLOG[p]["TYPE"] ": " _get_errout_i2(p) + if (match(_tLOG[p]["TEXT"], /\x1F/)) { + t = n + gsub(/[^\t]/, " ", t) + return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) + } } - } + return _ln(n _tLOG[p]["TEXT"]) + } +} + +#_______________________________________________________________________ +function _get_errout_i2(p) +{ + return (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) +} + +#_______________________________________________________________________ +function _get_errout_i3(p, t, ts, cl, cp, cr, a, b) +{ + if ("LSTR" in _tLOG[p]) { + t = _tLOG[p]["FULLSTR"] + ts = _tLOG[p]["TS"] + cp = "^" + if ("CSTR" in _tLOG[p]) { + cr = _tLOG[p]["CSTR"] + cl = _tLOG[p]["CLSTR"] + if ("CPSTR" in _tLOG[p]) { + cp = _tLOG[p]["CPSTR"] + } + } + cr = substr(cr, length(cl) + length(cp) + 1) + return (_ln(_tabtospc(t, ts)) _ln(_getchrln(" ", a = length(_tabtospc(_tLOG[p]["LSTR"], ts))) _getchrln("-", b = length(_tabtospc(cl, ts, a))) _getchrln("^", b = length(_tabtospc(cp, ts, a = a + b))) _getchrln("-", length(_tabtospc(cr, ts, a + b))))) + } +} - function _foreach_i0(A, f, D, p0, p1, p2) - { - for (i in A) { - if (isarray(A[i])) { - _foreach_i0(A[i], f, D, p0, p1, p2) - } else { - _gen(D, @f(A[i], p0, p1, p2)) +#_____________________________________________________________________________ +function _get_logout(p) +{ + ####################################################### + return _tframe("_get_logout_i0", p) +} + +#_______________________________________________________________________ +function _get_logout_i0(p, t, n, a) +{ + if (p in _tLOG) { + n = (("DATE" in _tLOG[p] ? _tLOG[p]["DATE"] " " : "")) (("TIME" in _tLOG[p] ? _tLOG[p]["TIME"] " " : "")) + if (_tLOG[p]["TYPE"]) { + n = n _tLOG[p]["TYPE"] ": " (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) + if (match(_tLOG[p]["TEXT"], /\x1F/)) { + t = n + gsub(/[^\t]/, " ", t) + return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) + } + } + return _ln(n _tLOG[p]["TEXT"]) + } +} + +#_______________________________________________________________________ +function _getchrln(s, w) +{ + ################################################# + if (s == "") { + return + } + #if ( w!=w+0 || w<0 ) w=_CON_WIDTH + if (length(s) < w) { + if (s in _GETCHRLN) { + if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) { + return substr(_getchrlnt0, 1, w) } - } + } else { + _getchrlnt0 = s s + } + while (length(_getchrlnt0) < w) { + _getchrlnt0 = _getchrlnt0 _getchrlnt0 + } + _GETCHRLN[s] = _getchrlnt0 + return substr(_getchrlnt0, 1, w) + } else { + return substr(s, 1, w) + } +} + +#_______________________________________________________________________ +function _getdate() +{ + ##################################################### + return strftime("%F") +} + +#_____________________________________________________________________________ +function _getfilepath(t, f, al, b, A) +{ + ############################################ + ERRNO = "" + if (match(t, /^[ \t]*(("([^"]*)"[ \t]*)|([`']([^']*)'[ \t]*)|(([^ \t]+)[ \t]*))/, A)) { + al = RLENGTH + f = A[3] A[5] A[7] + _conl("_getfilepath(" f ") (" al ")") + if (b = _filepath(f)) { + if (length(f) <= FLENGTH) { + FLENGTH = al + return b + } + ERRNO = "Filepath `" f "' error" + } + } + FLENGTH = 0 +} + +function _getfilever(f) +{ + ############################################################# + split(_cmd(_fileverpath " \"" f "\""), _GETFILEVERA0, /[ \t]+/) + if (_GETFILEVERA0[5]) { + return _GETFILEVERA0[5] + } +} + +#_________________________________________________________________ +function _getime() +{ + ################################################ + return strftime("%H:%M:%S") +} + +#_________________________________________________________________ +function _getmpdir(f, dd) +{ + ########################################## + if (! dd || ! (dd = _filerd(dd))) { + dd = _FILEIO_TMPRD + } + if (f = (f ? _filerd(f, dd) : _filerd("_" ++_FILEIO_TMPCNTR "\\", dd))) { + _FILEIO_RDTMP[toupper(f)] + } + return f +} + +#_________________________________________________________________ +function _getmpfile(f, dd) +{ + ######################################### + if (! dd || ! (dd = _filerd(dd))) { + dd = _FILEIO_TMPRD + } + if (f = _filerdne((_filene(f) ? f : f "_" ++_FILEIO_TMPCNTR), dd)) { + _FILEIO_RDNETMP[toupper(f)] + } + return f +} + +#_______________________________________________________________________ +function _getperf(o, t, a) +{ + ############################################### + (o == "" ? ++_getperf_opcurr : _getperf_opcurr = o) + if ((a = _getsecond()) != _getperf_last) { + _getperf_opsec = (_getperf_opcurr - _getperf_opstart) / ((_getperf_last = a) - _getperf_start) + return @_getperf_fn(o, t, a) + } + return 1 +} + +#___________________________________________________________ +function _getperf_(o, t, a) +{ + if (a >= _getperf_end) { + return 0 } - - function _foreach_i1(p, f, D, p0, p1, p2) - { - _gen(D, @f(p, p0, p1, p2)) + if (_getperf_opsecp != _getperf_opsec) { + _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") + _getperf_stat = _constatstr + } + return 1 +} + +#___________________________________________________________ +function _getperf_noe(o, t, a) +{ + if (_getperf_opsecp != _getperf_opsec) { + _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") + _getperf_stat = _constatstr + } + return 1 +} + +#___________________________________________________________ +function _getperf_noenot(o, t, a) +{ + return 1 +} + +#___________________________________________________________ +function _getperf_not(o, t, a) +{ + if (a < _getperf_end) { + return 1 } +} - function _formatrexp(t) - { - _formatstrq0 = split(t, _FORMATSTRA, /[\/\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATREXPESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } +#_________________________________________________________________________________________ +########################################################################################## - function _formatrexp_init() - { - _defescarr(_FORMATREXPESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATREXPESC, "\\/", "\\") - _FORMATREXPESC["\t"] = "\\t" - } - function _formatstrd(t) - { - _formatstrq0 = split(t, _FORMATSTRA, /["\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRDESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _formatstrd_init() - { - _defescarr(_FORMATSTRDESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATSTRDESC, "[\\\\\"]", "\\") - _FORMATSTRDESC["\t"] = "\\t" - } - function _formatstrs(t) - { - _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRSESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _formatstrs_init() - { - _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATSTRSESC, "[\\\\']", "\\") - _FORMATSTRSESC["\t"] = "\\t" - } - function _fpp(q, D, S) - { - _conl() - _conline(q) - _conl() - q = _patharr0(S, q) - _conl(_dumparr(S)) - _conl() - return q - } - function _fthru(A, c, p, B) - { - return _fthru_i0(A, c, p, B, A[""]) - } - function _fthru_i0(A, c, p, B, f) - { - return ((f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : "")) - } - function _gen(D, t) - { - if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) { - D[++D[_ARRLEN]] = "" - } - } - function _gensubfn(t, r, f, p0, A) - { - if (match(t, r, A)) { - return (substr(t, 1, RSTART - 1) (@f(_th0(substr(t, RSTART, RLENGTH), t = substr(t, RSTART + RLENGTH)), A, p0)) _gensubfn(t, r, f, p0)) - } - return t - } - function _get_errout(p) - { - return _tframe("_get_errout_i0", p) - } - function _get_errout_i0(p, t, n, a) - { - return ((p in _tLOG ? _get_errout_i1(p) _get_errout_i3(p) : "")) - } - function _get_errout_i1(p, t, n, a) - { - if (p in _tLOG) { - n = "" - if (_tLOG[p]["TYPE"]) { - n = _tLOG[p]["TYPE"] ": " _get_errout_i2(p) - if (match(_tLOG[p]["TEXT"], /\x1F/)) { - t = n - gsub(/[^\t]/, " ", t) - return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) - } - } - return _ln(n _tLOG[p]["TEXT"]) - } - } - function _get_errout_i2(p) - { - return (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) - } - function _get_errout_i3(p, t, ts, cl, cp, cr, a, b) - { - if ("LSTR" in _tLOG[p]) { - t = _tLOG[p]["FULLSTR"] - ts = _tLOG[p]["TS"] - cp = "^" - if ("CSTR" in _tLOG[p]) { - cr = _tLOG[p]["CSTR"] - cl = _tLOG[p]["CLSTR"] - if ("CPSTR" in _tLOG[p]) { - cp = _tLOG[p]["CPSTR"] - } - } - cr = substr(cr, length(cl) + length(cp) + 1) - return (_ln(_tabtospc(t, ts)) _ln(_getchrln(" ", a = length(_tabtospc(_tLOG[p]["LSTR"], ts))) _getchrln("-", b = length(_tabtospc(cl, ts, a))) _getchrln("^", b = length(_tabtospc(cp, ts, a = a + b))) _getchrln("-", length(_tabtospc(cr, ts, a + b))))) - } - } - function _get_logout(p) - { - return _tframe("_get_logout_i0", p) - } - function _get_logout_i0(p, t, n, a) - { - if (p in _tLOG) { - n = (("DATE" in _tLOG[p] ? _tLOG[p]["DATE"] " " : "")) (("TIME" in _tLOG[p] ? _tLOG[p]["TIME"] " " : "")) - if (_tLOG[p]["TYPE"]) { - n = n _tLOG[p]["TYPE"] ": " (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) - if (match(_tLOG[p]["TEXT"], /\x1F/)) { - t = n - gsub(/[^\t]/, " ", t) - return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) - } - } - return _ln(n _tLOG[p]["TEXT"]) - } - } - function _getchrln(s, w) - { - if (s == "") { - return - } - if (length(s) < w) { - if (s in _GETCHRLN) { - if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) { - return substr(_getchrlnt0, 1, w) - } - } else { - _getchrlnt0 = s s - } - while (length(_getchrlnt0) < w) { - _getchrlnt0 = _getchrlnt0 _getchrlnt0 - } - _GETCHRLN[s] = _getchrlnt0 - return substr(_getchrlnt0, 1, w) - } else { - return substr(s, 1, w) - } - } - function _getdate() - { - return strftime("%F") - } - function _getfilepath(t, f, al, b, A) - { - ERRNO = "" - if (match(t, /^[ \t]*(("([^"]*)"[ \t]*)|([`']([^']*)'[ \t]*)|(([^ \t]+)[ \t]*))/, A)) { - al = RLENGTH - f = A[3] A[5] A[7] - _conl("_getfilepath(" f ") (" al ")") - if (b = _filepath(f)) { - if (length(f) <= FLENGTH) { - FLENGTH = al - return b - } - ERRNO = "Filepath `" f "' error" + +function _getreg_i1(D, r, R, a, i, il, ir, rc, B) +{ + a = IGNORECASE + IGNORECASE = 1 + r = "^" _torexp(r) + rc = 0 + zs = "" + for (i in R) { + if (match(i, r, B)) { + il = B[_torexp_pfxcntr] + ir = gensub(/....$/, "", 1, substr(i, 1 + B[_torexp_pfxcntr, "length"])) + if (! gsub(/^\\/, "", ir) && match(il, /[^\\]+$/)) { + ir = substr(il, RSTART) ir } + D[ir] = R[i] + rc++ } - FLENGTH = 0 } - - function _getfilever(f) - { - split(_cmd(_fileverpath " \"" f "\""), _GETFILEVERA0, /[ \t]+/) - if (_GETFILEVERA0[5]) { - return _GETFILEVERA0[5] - } + IGNORECASE = a + if (rc > 0) { + return rc } +} - function _getime() - { - return strftime("%H:%M:%S") - } +#_________________________________________________________________ +function _getsecond() +{ + ############################################# + return systime() +} - function _getmpdir(f, dd) - { - if (! dd || ! (dd = _filerd(dd))) { - dd = _FILEIO_TMPRD - } - if (f = (f ? _filerd(f, dd) : _filerd("_" ++_FILEIO_TMPCNTR "\\", dd))) { - _FILEIO_RDTMP[toupper(f)] - } - return f +#___________________________________________________________ +function _getsecondsync(a, c, b, c2) +{ + ########################## + a = systime() + while (a == systime()) { + ++c } + return (a + 1) +} - function _getmpfile(f, dd) - { - if (! dd || ! (dd = _filerd(dd))) { - dd = _FILEIO_TMPRD +#_______________________________________________________________________ +function _getuid(p) +{ + ################################################# 1 # + if (p in _UIDOBL) { + for (_tptr in _UIDOBLV[_getuida0 = _UIDOBL[p]]) { + delete _UIDOBLV[_getuida0][_tptr] + _CLASSPTR[_tptr] = p + return _tptr } - if (f = _filerdne((_filene(f) ? f : f "_" ++_FILEIO_TMPCNTR), dd)) { - _FILEIO_RDNETMP[toupper(f)] - } - return f } + _CLASSPTR[_tptr = _UIDPFX[p] _getuid_i0(_UIDCNT[p], _UIDCHRL[_tptr = _UIDCHR[p]], _UIDCHRH[_tptr]) _UIDSFX[p]] = p + return _tptr +} - function _getperf(o, t, a) - { - (o == "" ? ++_getperf_opcurr : _getperf_opcurr = o) - if ((a = _getsecond()) != _getperf_last) { - _getperf_opsec = (_getperf_opcurr - _getperf_opstart) / ((_getperf_last = a) - _getperf_start) - return @_getperf_fn(o, t, a) +#_____________________________________________________ +function _getuid_i0(p, UL, UH) +{ + if ("" == (_tptr = UL[_UIDCNTL[p]])) { + for (_tptr in UH) { + delete UH[_tptr] + return ((_UIDCNTH[p] = _tptr) (_UIDCNTL[p] = UL[""])) } - return 1 + _fatal("out of UID") } + return (_UIDCNTH[p] (_UIDCNTL[p] = _tptr)) +} - function _getperf_(o, t, a) - { - if (a >= _getperf_end) { - return 0 - } - if (_getperf_opsecp != _getperf_opsec) { - _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") - _getperf_stat = _constatstr - } - return 1 - } +function _handle8494(t) +{ + return gensub(/(.)/, ".\\1", "G", t) +} - function _getperf_noe(o, t, a) - { - if (_getperf_opsecp != _getperf_opsec) { - _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") - _getperf_stat = _constatstr - } - return 1 +#_____________________________________________________________________________ +function _hexnum(n, l) +{ + ######################################################### + if (l + 0 < 1) { + l = 2 } + return sprintf("%." ((l + 0 < 1 ? 2 : l)) "X", n) +} - function _getperf_noenot(o, t, a) - { - return 1 +#_________________________________________________________________ +function _igetperf(t, s, o) +{ + ######################################### # t-test period in seconds(==0 ? no period; s(=true/false)-output/not output status; o-qnt of ops before test start + if (t == 0 && t == "" && s == 0 && s == "" && o == 0 && o == "") { + if (_getperf_fn !~ /not$/ && _constatstr == _getperf_stat) { + _constat(_getperf_statstr) + } + _getperf_fn = "_nop" + return ("[TIME=" (_getperf_last - _getperf_start) " sec(" _getperf_opsec " ops/sec)]") + } + _conl("initiate _getperf") + _getperf_opstart = _getperf_opcurr = o + 0 + _getperf_opsec = _getperf_opsecp = _getperf_stat = _getperf_statstr = "" + _getperf_end = t + (_getperf_start = _getperf_last = _getsecondsync()) + _getperf_fn = ((t + 0 > 0 ? "_getperf_" : "_getperf_noe")) ((s ? "" : "not")) + return _getperf_start +} + +function _import_data(t, p, p2, a) +{ + if (match(t, /^_DATA: /)) { + _tDATA[a = _wLCHLD(p, _N())][""] + delete _tDATA[a][""] + _Zimparr(_tDATA[a], substr(t, 8)) + _conl("DATA: `" _tDATA[a]["ID"] "':`" _tDATA[a]["DATA"] "'") + return "" } - - function _getperf_not(o, t, a) - { - if (a < _getperf_end) { - return 1 + return t +} + +#_______________________________________________________________________ +function _info(t, d, A) +{ + ################################################## + if (_ERRLOG_IF) { + A["TYPE"] = "INFO" + A["TEXT"] = t + _log(A, d) + } +} + +# test with the different path types +# _conl(_ln("SRC:") _dumparr(S)); _conl(); + +function _ini(p, cs, dptr, pfx, sfx, hstr, lstr) +{ + return _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) +} + +function _initfilever() +{ + _fileverpath = "\\\\CPU\\eGAWK\\LIB\\_filever\\_filever.exe" +} + +function _initrdreg() +{ + _RDREGTYPE["SZ"] = "STR" + _RDREGTYPE["DWORD"] = "W32" + _RDREGTYPE["QWORD"] = "W64" + _RDREGTYPE["BINARY"] = "BIN" + _RDREGTYPE["EXPAND_SZ"] = "XSZ" + _RDREGTYPE["MULTI_SZ"] = "MSZ" + _RDrdregfld = _rdregkey = 0 +} + +function _initregpath0() +{ + _REGPATH0REGDIR[""] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKLM"] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKEY_LOCAL_MACHINE"] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKCR"] = "HKEY_CLASSES_ROOT" + _REGPATH0REGDIR["HKEY_CLASSES_ROOT"] = "HKEY_CLASSES_ROOT" + _REGPATH0REGDIR["HKCU"] = "HKEY_CURRENT_USER" + _REGPATH0REGDIR["HKEY_CURRENT_USER"] = "HKEY_CURRENT_USER" + _REGPATH0REGDIR["HKU"] = "HKEY_USERS" + _REGPATH0REGDIR["HKEY_USERS"] = "HKEY_USERS" + _REGPATH0REGDIR["HKCC"] = "HKEY_CURRENT_CONFIG" + _REGPATH0REGDIR["HKEY_CURRENT_CONFIG"] = "HKEY_CURRENT_CONFIG" + _REGPATH0REGDIR["HKPD"] = "HKEY_PERFORMANCE_DATA" + _REGPATH0REGDIR["HKEY_PERFORMANCE_DATA"] = "HKEY_PERFORMANCE_DATA" +} + +function _initshare() +{ + _sharextool = "\\\\CPU\\eGAWK\\LIB\\_share\\_share.exe" +} + +#_________________________________________ +function _initspecialuid() +{ + _NOINDEX = _getuid() + _LEN = _getuid() + _PTR = _getuid() + _NAME = _getuid() + _TYPE = _getuid() + _FORMAT = _getuid() +} + +function _initsys() +{ +} + +#_______________________________________________________________________ +function _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) +{ + ################### 1 # + if (cs == 0 && cs == "") { + cs = p + p = _getuid() + } + _conl() + _conl() + _conl(cs) + if (match(cs, /^(([^:]*):)?(([^'\xB4]*\xB4.)*[^'\xB4]*)[']/, A)) { + pfx = A[3] + dptr = A[2] + } + if (match(cs = substr(cs, 1 + RLENGTH), /'(([^'\xB4]*\xB4.)*[^'\xB4]*)$/, A)) { + sfx = A[1] + cs = substr(cs, 1, RSTART - 1) + } + if (match(cs, /^(([`\^])(.*))/, A)) { + if (A[2] == "`") { + hstr = A[3] "~" + lstr = "" + } else { + lstr = A[3] "+" + hstr = "" + } + } else { + if (match(cs, /^(([^'\xB4\|]*\xB4.)*[^'\xB4\|]*)(\|(.*))?/, A)) { + hstr = A[1] + lstr = A[4] + } else { + ERRNO = "_inituid(): bad parameters" + return } } - - function _getreg_i1(D, r, R, a, i, il, ir, rc, B) - { - a = IGNORECASE - IGNORECASE = 1 - r = "^" _torexp(r) - rc = 0 - zs = "" - for (i in R) { - if (match(i, r, B)) { - il = B[_torexp_pfxcntr] - ir = gensub(/....$/, "", 1, substr(i, 1 + B[_torexp_pfxcntr, "length"])) - if (! gsub(/^\\/, "", ir) && match(il, /[^\\]+$/)) { - ir = substr(il, RSTART) ir + _conl(dptr ":" pfx "'" hstr "|" lstr "'" sfx) + return _cfguid(p, dptr, pfx, sfx, hstr, lstr) +} + +function _inituidefault(h, l, H, L) +{ + _classys = "" + delete _UIDOBLV[_UIDOBLV[_UIDOBL[_classys] = _classys][""] = _classys][""] + _UIDPFX[_classys] + _UIDSFX[_classys] + _UIDCNT[_classys] = _UIDCHR[_classys] = _CLASSPTR[_classys] = _classys + h = "AB" + l = h "01" + _splitstr(H, h) + _splitstr(L, l) + delete _UIDCHRH[_UIDCHRH[_classys][""] = _classys][""] + delete _UIDCHRL[_UIDCHRL[_classys][""] = _classys][""] + _UIDCNTH[_classys] + _cfguidh(_classys, H, L) + _UIDCNTL[_classys] = _cfguidl(_classys, L, L) + _CLASSFN[_classys]["del"] = "_tobjDEL" + _CLASSFN[_classys]["new"] = "_tobjNEW" + _drawuid(_classys) + _initspecialuid() +} + +#_______________________________________________________________________ +function _ins(S, sf, D, df) +{ + ################################################ + if (sf in S) { + if (isarray(S[sf])) { + if (df in D) { + if (isarray(D[df])) { + return _extarr(D[df], S[sf]) } - D[ir] = R[i] - rc++ + delete D[df] } - } - IGNORECASE = a - if (rc > 0) { - return rc - } + D[df][""] + delete D[df][""] + return _extarr(D[df], S[sf]) + } else { + if (isarray(D[df])) { + delete D[df] + } + D[df] = S[sf] D[df] + } + } +} + +#_________________________________________________________________ +function _insf(A, f) +{ + ############################################### + A["F"][""] = A["B"][A["F"][f] = A["F"][""]] = f +} + +#_________________________________________________________________ +function _insframe(A, f) +{ + ########################################### + A[f] = A[""] + A[""] = f +} + +######################## +#_________________________________________________________________ +function _inspass(A, f) +{ + A[f] = A[""] + A[""] = f +} + +# there is problem with string's format: i can;t easilly merge 2 charsets: comma-divided and every-char-divided strings + +#_______________________________________________________________________ +function _isptr(p) +{ + ################################################## 1 # + if (isarray(p)) { + is = _NOP + it = "A" + return 0 } - - function _getsecond() - { - return systime() + is = p + if (p == 0 && p == "") { + it = "-" + return 0 } - - function _getsecondsync(a, c, b, c2) - { - a = systime() - while (a == systime()) { - ++c - } - return (a + 1) + if (p in _CLASSPTR) { + return (it = "P") } + it = "S" + return 0 +} - function _getuid(p) - { - if (p in _UIDOBL) { - for (_tptr in _UIDOBLV[_getuida0 = _UIDOBL[p]]) { - delete _UIDOBLV[_getuida0][_tptr] - _CLASSPTR[_tptr] = p - return _tptr - } +#_______________________________________________________________________ +function _istr(p) +{ + ################################################### 1 # + if (isarray(p)) { + is = _NOP + it = "A" + return 0 + } + is = p + if (p == 0 && p == "") { + it = "-" + return 0 + } + return (it = (p == "" ? "s" : "S")) +} + +#_________________________________________________________________ +function _lengthsort(i1, v1, i2, v2) +{ + ############################## + return ((length(i1) < length(i2) ? -1 : (length(i1) > length(i2) ? 1 : (i1 < i2 ? -1 : 1)))) +} + +#_________________________________________________________________ +function _lib_APPLY() +{ + return _ffaccr(_LIBAPI, "_lib_APPLY") +} + +#_________________________________________________________________ +function _lib_BEGIN(A) +{ + return _ffaccr(_LIBAPI, "_lib_BEGIN", "", A) +} + +#_______________________________________________________________________ +function _lib_CMDLN(t) +{ + return _pass(_LIBAPI["F"], "_lib_CMDLN", t) +} + +#_________________________________________________________________ +function _lib_END(A) +{ + return _ffaccr(_LIBAPI, "_lib_END", "", A) +} + +#_________________________________________________________________ +function _lib_HELP() +{ + return _fbaccr(_LIBAPI, "_lib_HELP") +} + +#_________________________________________________________________ +function _lib_NAMEVER() +{ + return _fbaccr(_LIBAPI, "_lib_NAMEVER") +} + +#_____________________________________________________________________________ +function _ln(t) +{ + ############################################################### + return ((t ~ /\x0A$/ ? t : t _CHR["EOL"])) +} + +#_________________________________________________________________ +function _log(A, p, a, B) +{ + ########################################### + if (isarray(A)) { + A["TIME"] = _getime() + A["DATE"] = _getdate() + if (p) { + _tLOG[p = _wLCHLD(p, _N())][""] + delete _tLOG[p][""] + _movarr(_tLOG[p], A) + return p } - _CLASSPTR[_tptr = _UIDPFX[p] _getuid_i0(_UIDCNT[p], _UIDCHRL[_tptr = _UIDCHR[p]], _UIDCHRH[_tptr]) _UIDSFX[p]] = p - return _tptr + _expout("_ERRLOG: " _Zexparr(A) "\n") + } else { + B["TEXT"] = A + B["TYPE"] = "" + return _log(B, p) } +} - function _getuid_i0(p, UL, UH) - { - if ("" == (_tptr = UL[_UIDCNTL[p]])) { - for (_tptr in UH) { - delete UH[_tptr] - return ((_UIDCNTH[p] = _tptr) (_UIDCNTL[p] = UL[""])) +#_________________________________________________________________ +function _lspctab(t, ts, l, l1, l2, A) +{ + ################################ + while (match(t, /^(\t*)( *)((\t*)(.*))$/, A)) { + if (A[1, "length"] >= l) { + return substr(t, l + 1) + } + if (A[2]) { + if ((l1 = int(A[2, "length"] / ts)) >= (l2 = l - A[1, "length"])) { + return (substr(A[2], l2 * ts + 1) A[3]) } - _fatal("out of UID") + if (! A[4]) { + return A[5] + } + t = A[1] _getchrln("\t", l1) A[3] + } else { + return t } - return (_UIDCNTH[p] (_UIDCNTL[p] = _tptr)) } - - function _handle8494(t) - { - return gensub(/(.)/, ".\\1", "G", t) +} + +function _mac_init() +{ + _MACPFX["\204"] = "_macpfx84" + _MACPFX[""] = "_mpupfxsubret" + _MACPFX84SFX["\204"] = "_macpfx84" + _MACPFX84SFX["\224"] = "_macsfx94" + _MACPFX84SFX[""] = "_mpusfxsubret" + _VLDMAXSTRING = 1e+06 +} + +function _macpfx84(F, D, C, p1, p2, p3) +{ + return _mpusub(_MACPFX84SFX, D, C, D[_mpuptr++], p1, p2, p3) +} + +function _macsfx94(F, D, C, p1, p2, p3) +{ + return _mpuretsub(D, _handle8494(_mpuacc)) +} + +#_______________________________________________________________________ +function _movarr(D, S) +{ + ################################################### + delete D + D[""] + delete D[""] + _addarr(D, S) +} + +function _mpu(t, F, p1, p2, p3, D, C) +{ + if (patsplit(t, C, /[\x84\x93\x94]/, D) > 0) { + _conline("CODE") + _conl() + _conl(_dumparr(C)) + _conline("DATA") + _conl() + _conl(_dumparr(D)) + _mpuptr = 0 + _mpucc0 = "" + _mpusub(F, D, C, D[_mpuptr++], p1, p2, p3) + return _mpuacc } + return t +} - function _hexnum(n, l) - { - if (l + 0 < 1) { - l = 2 - } - return sprintf("%." ((l + 0 < 1 ? 2 : l)) "X", n) - } +# +# /rexpstr/ -> datastr +# (\x00\t\+)* -> 28 00 09 5B 2B 29 +# +# unesc all non-rexp characters: replace unesc of rexp-characters but do not remove it: \* -> \*, \x2A -> \*, \052 -> \*, \\ -> \# - function _igetperf(t, s, o) - { - if (t == 0 && t == "" && s == 0 && s == "" && o == 0 && o == "") { - if (_getperf_fn !~ /not$/ && _constatstr == _getperf_stat) { - _constat(_getperf_statstr) - } - _getperf_fn = "_nop" - return ("[TIME=" (_getperf_last - _getperf_start) " sec(" _getperf_opsec " ops/sec)]") - } - _conl("initiate _getperf") - _getperf_opstart = _getperf_opcurr = o + 0 - _getperf_opsec = _getperf_opsecp = _getperf_stat = _getperf_statstr = "" - _getperf_end = t + (_getperf_start = _getperf_last = _getsecondsync()) - _getperf_fn = ((t + 0 > 0 ? "_getperf_" : "_getperf_noe")) ((s ? "" : "not")) - return _getperf_start - } - - function _import_data(t, p, p2, a) - { - if (match(t, /^_DATA: /)) { - _tDATA[a = _wLCHLD(p, _N())][""] - delete _tDATA[a][""] - _Zimparr(_tDATA[a], substr(t, 8)) - _conl("DATA: `" _tDATA[a]["ID"] "':`" _tDATA[a]["DATA"] "'") - return "" - } - return t - } - function _info(t, d, A) - { - if (_ERRLOG_IF) { - A["TYPE"] = "INFO" - A["TEXT"] = t - _log(A, d) - } - } - function _ini(p, cs, dptr, pfx, sfx, hstr, lstr) - { - return _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) - } - function _initfilever() - { - _fileverpath = "\\\\CPU\\eGAWK\\LIB\\_filever\\_filever.exe" - } - function _initrdreg() - { - _RDREGTYPE["SZ"] = "STR" - _RDREGTYPE["DWORD"] = "W32" - _RDREGTYPE["QWORD"] = "W64" - _RDREGTYPE["BINARY"] = "BIN" - _RDREGTYPE["EXPAND_SZ"] = "XSZ" - _RDREGTYPE["MULTI_SZ"] = "MSZ" - _RDrdregfld = _rdregkey = 0 - } - function _initregpath0() - { - _REGPATH0REGDIR[""] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKLM"] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKEY_LOCAL_MACHINE"] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKCR"] = "HKEY_CLASSES_ROOT" - _REGPATH0REGDIR["HKEY_CLASSES_ROOT"] = "HKEY_CLASSES_ROOT" - _REGPATH0REGDIR["HKCU"] = "HKEY_CURRENT_USER" - _REGPATH0REGDIR["HKEY_CURRENT_USER"] = "HKEY_CURRENT_USER" - _REGPATH0REGDIR["HKU"] = "HKEY_USERS" - _REGPATH0REGDIR["HKEY_USERS"] = "HKEY_USERS" - _REGPATH0REGDIR["HKCC"] = "HKEY_CURRENT_CONFIG" - _REGPATH0REGDIR["HKEY_CURRENT_CONFIG"] = "HKEY_CURRENT_CONFIG" - _REGPATH0REGDIR["HKPD"] = "HKEY_PERFORMANCE_DATA" - _REGPATH0REGDIR["HKEY_PERFORMANCE_DATA"] = "HKEY_PERFORMANCE_DATA" - } - function _initshare() - { - _sharextool = "\\\\CPU\\eGAWK\\LIB\\_share\\_share.exe" - } - function _initspecialuid() - { - _NOINDEX = _getuid() - _LEN = _getuid() - _PTR = _getuid() - _NAME = _getuid() - _TYPE = _getuid() - _FORMAT = _getuid() - } - function _initsys() - { - } - function _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) - { - if (cs == 0 && cs == "") { - cs = p - p = _getuid() - } - _conl() - _conl() - _conl(cs) - if (match(cs, /^(([^:]*):)?(([^'\xB4]*\xB4.)*[^'\xB4]*)[']/, A)) { - pfx = A[3] - dptr = A[2] - } - if (match(cs = substr(cs, 1 + RLENGTH), /'(([^'\xB4]*\xB4.)*[^'\xB4]*)$/, A)) { - sfx = A[1] - cs = substr(cs, 1, RSTART - 1) - } - if (match(cs, /^(([`\^])(.*))/, A)) { - if (A[2] == "`") { - hstr = A[3] "~" - lstr = "" - } else { - lstr = A[3] "+" - hstr = "" - } - } else { - if (match(cs, /^(([^'\xB4\|]*\xB4.)*[^'\xB4\|]*)(\|(.*))?/, A)) { - hstr = A[1] - lstr = A[4] - } else { - ERRNO = "_inituid(): bad parameters" - return - } - } - _conl(dptr ":" pfx "'" hstr "|" lstr "'" sfx) - return _cfguid(p, dptr, pfx, sfx, hstr, lstr) - } - - function _inituidefault(h, l, H, L) - { - _classys = "" - delete _UIDOBLV[_UIDOBLV[_UIDOBL[_classys] = _classys][""] = _classys][""] - _UIDPFX[_classys] - _UIDSFX[_classys] - _UIDCNT[_classys] = _UIDCHR[_classys] = _CLASSPTR[_classys] = _classys - h = "AB" - l = h "01" - _splitstr(H, h) - _splitstr(L, l) - delete _UIDCHRH[_UIDCHRH[_classys][""] = _classys][""] - delete _UIDCHRL[_UIDCHRL[_classys][""] = _classys][""] - _UIDCNTH[_classys] - _cfguidh(_classys, H, L) - _UIDCNTL[_classys] = _cfguidl(_classys, L, L) - _CLASSFN[_classys]["del"] = "_tobjDEL" - _CLASSFN[_classys]["new"] = "_tobjNEW" - _drawuid(_classys) - _initspecialuid() - } - - function _ins(S, sf, D, df) - { - if (sf in S) { - if (isarray(S[sf])) { - if (df in D) { - if (isarray(D[df])) { - return _extarr(D[df], S[sf]) - } - delete D[df] - } - D[df][""] - delete D[df][""] - return _extarr(D[df], S[sf]) - } else { - if (isarray(D[df])) { - delete D[df] - } - D[df] = S[sf] D[df] - } - } - } - function _insf(A, f) - { - A["F"][""] = A["B"][A["F"][f] = A["F"][""]] = f - } - function _insframe(A, f) - { - A[f] = A[""] - A[""] = f - } - function _inspass(A, f) - { - A[f] = A[""] - A[""] = f - } - function _isptr(p) - { - if (isarray(p)) { - is = _NOP - it = "A" - return 0 - } - is = p - if (p == 0 && p == "") { - it = "-" - return 0 - } - if (p in _CLASSPTR) { - return (it = "P") - } - it = "S" - return 0 - } - function _istr(p) - { - if (isarray(p)) { - is = _NOP - it = "A" - return 0 - } - is = p - if (p == 0 && p == "") { - it = "-" - return 0 - } - return (it = (p == "" ? "s" : "S")) - } - function _lengthsort(i1, v1, i2, v2) - { - return ((length(i1) < length(i2) ? -1 : (length(i1) > length(i2) ? 1 : (i1 < i2 ? -1 : 1)))) - } - function _lib_APPLY() - { - return _ffaccr(_LIBAPI, "_lib_APPLY") - } - function _lib_BEGIN(A) - { - return _ffaccr(_LIBAPI, "_lib_BEGIN", "", A) - } - function _lib_CMDLN(t) - { - return _pass(_LIBAPI["F"], "_lib_CMDLN", t) - } - function _lib_END(A) - { - return _ffaccr(_LIBAPI, "_lib_END", "", A) - } - function _lib_HELP() - { - return _fbaccr(_LIBAPI, "_lib_HELP") - } - function _lib_NAMEVER() - { - return _fbaccr(_LIBAPI, "_lib_NAMEVER") - } - function _ln(t) - { - return ((t ~ /\x0A$/ ? t : t _CHR["EOL"])) - } - function _log(A, p, a, B) - { - if (isarray(A)) { - A["TIME"] = _getime() - A["DATE"] = _getdate() - if (p) { - _tLOG[p = _wLCHLD(p, _N())][""] - delete _tLOG[p][""] - _movarr(_tLOG[p], A) - return p - } - _expout("_ERRLOG: " _Zexparr(A) "\n") - } else { - B["TEXT"] = A - B["TYPE"] = "" - return _log(B, p) - } - } - function _lspctab(t, ts, l, l1, l2, A) - { - while (match(t, /^(\t*)( *)((\t*)(.*))$/, A)) { - if (A[1, "length"] >= l) { - return substr(t, l + 1) - } - if (A[2]) { - if ((l1 = int(A[2, "length"] / ts)) >= (l2 = l - A[1, "length"])) { - return (substr(A[2], l2 * ts + 1) A[3]) - } - if (! A[4]) { - return A[5] - } - t = A[1] _getchrln("\t", l1) A[3] - } else { - return t - } - } - } - function _mac_init() - { - _MACPFX["\204"] = "_macpfx84" - _MACPFX[""] = "_mpupfxsubret" - _MACPFX84SFX["\204"] = "_macpfx84" - _MACPFX84SFX["\224"] = "_macsfx94" - _MACPFX84SFX[""] = "_mpusfxsubret" - _VLDMAXSTRING = 1e+06 - } - function _macpfx84(F, D, C, p1, p2, p3) - { - return _mpusub(_MACPFX84SFX, D, C, D[_mpuptr++], p1, p2, p3) - } - function _macsfx94(F, D, C, p1, p2, p3) - { - return _mpuretsub(D, _handle8494(_mpuacc)) - } - function _movarr(D, S) - { - delete D - D[""] - delete D[""] - _addarr(D, S) - } - function _mpu(t, F, p1, p2, p3, D, C) - { - if (patsplit(t, C, /[\x84\x93\x94]/, D) > 0) { - _conline("CODE") - _conl() - _conl(_dumparr(C)) - _conline("DATA") - _conl() - _conl(_dumparr(D)) - _mpuptr = 0 - _mpucc0 = "" - _mpusub(F, D, C, D[_mpuptr++], p1, p2, p3) - return _mpuacc - } - return t - } - function _mpudefaulthnd(F, D, C, p1, p2, p3) - { - _mpuretsub(D, _mpucc0) - } - function _mpupfxsubret(F, D, C, p1, p2, p3) - { - return 1 - } - function _mpuretsub(D, t) - { - _mpuacc = D[_mpuptr++] - _accmpu(D, t) - return 1 - } - function _mpusfxsubret(F, D, C, p1, p2, p3) - { - return -1 - } +function _mpudefaulthnd(F, D, C, p1, p2, p3) +{ + _mpuretsub(D, _mpucc0) +} - function _mpusub(F, D, C, d, p1, p2, p3, q) - { - q = D[_ARRLEN] - if (_VLDMAXSTRING < length(d)) { - D[--D[_ARRLEN]] = d - _mpuacc = "" +function _mpupfxsubret(F, D, C, p1, p2, p3) +{ + return 1 +} + +function _mpuretsub(D, t) +{ + _mpuacc = D[_mpuptr++] + _accmpu(D, t) + return 1 +} + +function _mpusfxsubret(F, D, C, p1, p2, p3) +{ + return -1 +} + +function _mpusub(F, D, C, d, p1, p2, p3, q) +{ + q = D[_ARRLEN] + if (_VLDMAXSTRING < length(d)) { + D[--D[_ARRLEN]] = d + _mpuacc = "" + } else { + _mpuacc = d + } + d = _mpucc0 + _conl("_mpusub enter: in `" _mpuacc "' / _mpuptr=" _mpuptr "'") + do { + if ((_mpucc0 = C[_mpuptr]) in F) { + if (isarray(F[_mpucc0])) { + _mpufn0 = F[_mpucc0] + } + _conl("FN: `" _mpucc0 "' > CALL: `" _mpufn0 "' : _mpuacc=" _mpuacc "'") } else { - _mpuacc = d - } - d = _mpucc0 - _conl("_mpusub enter: in `" _mpuacc "' / _mpuptr=" _mpuptr "'") - do { - if ((_mpucc0 = C[_mpuptr]) in F) { - if (isarray(F[_mpucc0])) { - _mpufn0 = F[_mpucc0] - } - _conl("FN: `" _mpucc0 "' > CALL: `" _mpufn0 "' : _mpuacc=" _mpuacc "'") - } else { - _mpufn0 = "_mpudefaulthnd" + _mpufn0 = "_mpudefaulthnd" + } + } while (! _accmpu(D, _mpuacc, @_mpufn0(F, D, C, p1, p2, p3))) + if (_mpufn0 == -1) { + _conl("WARNING: unclosed expression: `" d _mpuacc "'") + _mpuacc = d _mpuacc + } + _retarrm(D, q, "", (_mpufn0 == -1 ? _th0(d, _mpusubwrng("WARNING: unclosed expression", d _mpuacc)) : "")) + # collect: _mpuacc=_retarr(D) _mpuacc + _conl("mpusub exit: _mpuacc: `" _mpuacc "'") +} + +#_______________________________________________________________________ +function _n(F, v, p) +{ + ##################################################### + for (p in _UIDSDEL) { + delete _UIDSDEL[p] + delete _ptr[p] + delete _tPREV[p] + delete _tPARENT[p] + delete _tNEXT[p] + delete _tFCHLD[p] + delete _tQCHLD[p] + delete _tLCHLD[p] + delete _TMP0[p] + delete _TMP1[p] + delete _tLINK[p] + delete _tCLASS[p] + return _nN_i0(p, F, v) + } + for (p in _UIDS) { + delete _UIDS[p] + return _nN_i0(p, F, v) + } + return _nN_i0(_tgenuid(), F, v) +} + +#_____________________________________________________ +function _nN_i0(p, F, v) +{ + _[p][""] + delete _[p][""] + _ptr[p][""] + delete _ptr[p][""] + _TMP0[p][_ARRLEN] = _TMP1[p][_ARRLEN] = 0 + if (isarray(F)) { + delete F[p] + if (isarray(v)) { + F[p][""] + delete F[p][""] + _copyarr(F[p], v) + } else { + if (! (v == 0 && v == "")) { + F[p] = v } - } while (! _accmpu(D, _mpuacc, @_mpufn0(F, D, C, p1, p2, p3))) - if (_mpufn0 == -1) { - _conl("WARNING: unclosed expression: `" d _mpuacc "'") - _mpuacc = d _mpuacc } - _retarrm(D, q, "", (_mpufn0 == -1 ? _th0(d, _mpusubwrng("WARNING: unclosed expression", d _mpuacc)) : "")) - _conl("mpusub exit: _mpuacc: `" _mpuacc "'") - } - - function _n(F, v, p) - { - for (p in _UIDSDEL) { - delete _UIDSDEL[p] - delete _ptr[p] - delete _tPREV[p] - delete _tPARENT[p] - delete _tNEXT[p] - delete _tFCHLD[p] - delete _tQCHLD[p] - delete _tLCHLD[p] - delete _TMP0[p] - delete _TMP1[p] - delete _tLINK[p] - delete _tCLASS[p] - return _nN_i0(p, F, v) - } - for (p in _UIDS) { - delete _UIDS[p] - return _nN_i0(p, F, v) - } - return _nN_i0(_tgenuid(), F, v) - } - - function _nN_i0(p, F, v) - { - _[p][""] - delete _[p][""] - _ptr[p][""] - delete _ptr[p][""] - _TMP0[p][_ARRLEN] = _TMP1[p][_ARRLEN] = 0 - if (isarray(F)) { - delete F[p] + } else { + if (! (F == 0 && F == "")) { if (isarray(v)) { - F[p][""] - delete F[p][""] - _copyarr(F[p], v) + _[p][F][""] + delete _[p][F][""] + _copyarr(_[p][F], v) } else { - if (! (v == 0 && v == "")) { - F[p] = v - } - } - } else { - if (! (F == 0 && F == "")) { - if (isarray(v)) { - _[p][F][""] - delete _[p][F][""] - _copyarr(_[p][F], v) + if (v == 0 && v == "") { + _mpu(F, p) } else { - if (v == 0 && v == "") { - _mpu(F, p) - } else { - _[p][F] = v - } + _[p][F] = v } } } - return p } + return p +} - function _newclrdir(f) - { - if ((f = _filerd(f)) == "") { - return - } - _cmd("rd " f " /S /Q 2>NUL") +#_________________________________________________________________ +function _newclrdir(f) +{ + ############################################ + if ((f = _filerd(f)) == "") { + return + } + _cmd("rd " f " /S /Q 2>NUL") + _cmd("md " f " 2>NUL") + _WFILEROOTDIR[f] + return f +} + +#_______________________________________________________________________ +function _newdir(f) +{ + ##################################################### + if ((f = _filerd(f)) == "") { + return + } + if (! (f in _WFILEROOTDIR)) { _cmd("md " f " 2>NUL") _WFILEROOTDIR[f] - return f } - - function _newdir(f) - { - if ((f = _filerd(f)) == "") { + return f +} + +############################## +#_______________________________________________________________________ +function _nop(p0, p1, p2, p3) +{ +} + +#_____________________________________________________ +# _retarr(ARRAY,start,prefixtr,postfixtr) +# Return string collected from elements of ARRAY. +# The data elements in ARRAY have numeric indexes. By default it starts from element with index 1, but it is possible to locate elements starting from +# 0,-1,-.... The last data element in the ARRAY have the highest numeric index that is stored in ARRAY[_ARRLEN]. +# Optimized for very large data size. +# +# IN: ARRAY - source data array(is ARRAY is not array then return undefined) +# start - (optional) start index in ARRAY; if missed or have non-numeric value then start array index will be 1. +# prefixst - the string that will be inserted in the begin of generated return string +# postfix - the string that will be added at the end of generated return string +# MOD: - +# OUT: - +# RETURN: undefined - if ARRAY is not array; if ARRAY is empty; if start is higher than ARRAY last element index +# string - collected string: prefixtr-arraydata-postfixtr +#_________________________________________________________________ +function _nretarr(A, i, v, r, q) +{ + ##################################### + if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { + if (i <= (r = q - 16)) { + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + while (i < r) { + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + } + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) return } - if (! (f in _WFILEROOTDIR)) { - _cmd("md " f " 2>NUL") - _WFILEROOTDIR[f] - } - return f - } - - function _nop(p0, p1, p2, p3) - { + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + return } - - function _nretarr(A, i, v, r, q) - { - if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { - if (i <= (r = q - 16)) { - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - while (i < r) { - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - } - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) - return - } + _ARRSTR = v + return +} + +#___________________________________________________________ +function _nretarrd(A, i, v, r, q) +{ + ############################## + if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { + if (i <= (r = q - 16)) { + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + while (i < r) { + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + } + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + } else { _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) - return } + } else { _ARRSTR = v - return } - - function _nretarrd(A, i, v, r, q) - { - if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { - if (i <= (r = q - 16)) { - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - while (i < r) { - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + delete A + A[""] + delete A[""] +} + +#___________________________________________________________________________________ +#################################################################################### + +#___________________________________________________________________________________ +function _out(t, a, b) +{ + ############################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > _SYS_STDOUT + fflush(_SYS_STDOUT) + BINMODE = a + ORS = b + return t +} + +#_________________________________________________________________ +function _outnl(t) +{ + ################################################ + return _out(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) +} + +function _p1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s1, p1, p2, p3, p4, p5, p6, p7) +} + +function _p2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s2, p1, p2, p3, p4, p5, p6, p7) +} + +function _p3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s3, p1, p2, p3, p4, p5, p6, p7) +} + +function _p4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s4, p1, p2, p3, p4, p5, p6, p7) +} + +function _p5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s5, p1, p2, p3, p4, p5, p6, p7) +} + +function _p6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s6, p1, p2, p3, p4, p5, p6, p7) +} + +function _p7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s7, p1, p2, p3, p4, p5, p6, p7) +} + +function _p8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s8, p1, p2, p3, p4, p5, p6, p7) +} + +#_______________________________________________________________________ +function _pass(A, f, t, p2, i, a) +{ + ########################################### + a = _endpass_v0 + _endpass_v0 = "" + i = 1 + while (t && i) { + i = "" + while ((i = A[i]) && t == (t = @i(f, t, p2))) { + } + } + if (i && _endpass_v0) { + A["!"] = 1 + t = _endpass_v0 + } else { + delete A["!"] + } + _endpass_v0 = a + return t +} + +# this is somnitelno: that / / . / / com 56 / / - is the DEV...; what is DEV ??? this already PROBLEM +#_____________________________________________________________________________ +function _patharr0(D, q, i, h, A, B) +{ + ############################################## + delete D + if (0 < (q = split(gensub(/\\/, "/", "G", gensub(/ *([:$\\\/]) */, "\\1", "G", gensub(/(^[ \t]+)|([ \t]+$)/, "", "G", q))), A, /\/+/, B))) { + if (2 > (h = length(B[1]))) { + D["type"] = "FILE" + A[1] = _patharr0_i0(A[1], D, "drive") + return _patharr0_i1(D, A, 1, q) + } + i = gensub(/ *([\.\?]) */, "\\1", "G", A[2]) + IGNORECASE = 1 + match(A[1], /^((https?)|(ftp)):$/) + IGNORECASE = 0 + if (RLENGTH > 0) { + D["type"] = toupper(substr(A[1], 1, RLENGTH - 1)) + _patharr0_i0(i, D, "site", "port") + } else { + if (A[1] == "") { + D["type"] = "UNC" + if (h > 2) { + D["host"] + A[2] = _patharr0_i0(A[2], D, "drive", "", "FILE") + return _patharr0_i1(D, A, 2, q) } - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + if (i == "") { + return 1 + } + D["host"] = i + A[3] = _patharr0_i0(A[3], D, "drive", "", "FILE") } else { - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + D["type"] = "FILE" + A[1] = _patharr0_i0(A[1], D, "drive") + return _patharr0_i1(D, A, 1, q) } - } else { - _ARRSTR = v } - delete A - A[""] - delete A[""] + return _patharr0_i1(D, A, 3, q) } +} - function _out(t, a, b) - { - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > _SYS_STDOUT - fflush(_SYS_STDOUT) - BINMODE = a - ORS = b +#_____________________________________________________ +function _patharr0_i0(t, D, l, r, d, i) +{ + if (i = index(t, ":")) { + if (d) { + D["type"] = d + } + if (i > 1) { + D[l] = substr(t, 1, i - 1) + } + if ((t = substr(t, i + 1)) && r) { + D[r] = t + } return t + } else { + if (t && r) { + D[l] = t + } } + return t +} - function _outnl(t) - { - return _out(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) - } - - function _p1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s1, p1, p2, p3, p4, p5, p6, p7) +#_____________________________________________________ +function _patharr0_i1(D, A, i, q, t, c) +{ + if (D["type"] == "UNC") { + if (t = A[i++]) { + D[0] = (D["share"] = D[++c] = t) "/" + } else { + return 1 + } } - - function _p2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s2, p1, p2, p3, p4, p5, p6, p7) + while (i < q) { + D[0] = D[0] (D[++c] = A[i++]) "/" } - - function _p3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s3, p1, p2, p3, p4, p5, p6, p7) + if (i == q) { + if (match(t = A[i], /\.[^\.]*$/)) { + if (RSTART > 1) { + D["name"] = substr(t, 1, RSTART - 1) + } + D["ext"] = substr(t, RSTART, RLENGTH) + } else { + if (t != "") { + D["name"] = t + } + } } + return 1 +} - function _p4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s4, p1, p2, p3, p4, p5, p6, p7) - } +############################################################################# - function _p5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s5, p1, p2, p3, p4, p5, p6, p7) - } - function _p6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s6, p1, p2, p3, p4, p5, p6, p7) - } - function _p7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { +function _pmap(m, s1, s2, s3, s4, s5, s6, s7, s8) +{ + if (match(m, /^([^\(]+)\(([^\)]*)\)$/, _QMAP)) { + _qparamf1 = _QMAP[1] + _QMAP[0] = "r" (_qparamc1 = split(_QMAP[2], _QMAP, "")) _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s7, p1, p2, p3, p4, p5, p6, p7) - } - - function _p8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s8, p1, p2, p3, p4, p5, p6, p7) - } - - function _pass(A, f, t, p2, i, a) - { - a = _endpass_v0 - _endpass_v0 = "" - i = 1 - while (t && i) { - i = "" - while ((i = A[i]) && t == (t = @i(f, t, p2))) { + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8) + } +} + +function _pr0(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1() +} + +function _pr1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1) +} + +function _pr2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2) +} + +function _pr3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3) +} + +function _pr4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4) +} + +function _pr5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5) +} + +function _pr6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6) +} + +function _pr7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6, p7) +} + +function _pr8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6, p7, p8) +} + +#_________________________________________________________________ +function _printarr(A, t, lv, r, a) +{ + #################################### + a = PROCINFO["sorted_in"] + PROCINFO["sorted_in"] = "_lengthsort" + _printarrexp = (r ? r : "") + if (isarray(A)) { + delete _DUMPARR + _dumparrc = _dumparrd = "" + _printarr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) + PROCINFO["sorted_in"] = a + return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") + } +} + +#___________________________________________________________ +function _printarr_i1(A, lv, ls, ln, t, t2, i, a, f) +{ + t2 = _getchrln(" ", length(t)) + if (ln == lv) { + if (ls > 0) { + for (i in A) { + ++a } - } - if (i && _endpass_v0) { - A["!"] = 1 - t = _endpass_v0 } else { - delete A["!"] + for (i in A) { + (isarray(A[i]) ? ++a : "") + } } - _endpass_v0 = a - return t + if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" + } + return } - - function _patharr0(D, q, i, h, A, B) - { - delete D - if (0 < (q = split(gensub(/\\/, "/", "G", gensub(/ *([:$\\\/]) */, "\\1", "G", gensub(/(^[ \t]+)|([ \t]+$)/, "", "G", q))), A, /\/+/, B))) { - if (2 > (h = length(B[1]))) { - D["type"] = "FILE" - A[1] = _patharr0_i0(A[1], D, "drive") - return _patharr0_i1(D, A, 1, q) - } - i = gensub(/ *([\.\?]) */, "\\1", "G", A[2]) - IGNORECASE = 1 - match(A[1], /^((https?)|(ftp)):$/) - IGNORECASE = 0 - if (RLENGTH > 0) { - D["type"] = toupper(substr(A[1], 1, RLENGTH - 1)) - _patharr0_i0(i, D, "site", "port") - } else { - if (A[1] == "") { - D["type"] = "UNC" - if (h > 2) { - D["host"] - A[2] = _patharr0_i0(A[2], D, "drive", "", "FILE") - return _patharr0_i1(D, A, 2, q) - } - if (i == "") { - return 1 + if (ls >= 0) { + for (i in A) { + if (! _printarrexp || i ~ _printarrexp) { + if (! isarray(A[i])) { + if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" } - D["host"] = i - A[3] = _patharr0_i0(A[3], D, "drive", "", "FILE") - } else { - D["type"] = "FILE" - A[1] = _patharr0_i0(A[1], D, "drive") - return _patharr0_i1(D, A, 1, q) } } - return _patharr0_i1(D, A, 3, q) } } - - function _patharr0_i0(t, D, l, r, d, i) - { - if (i = index(t, ":")) { - if (d) { - D["type"] = d - } - if (i > 1) { - D[l] = substr(t, 1, i - 1) - } - if ((t = substr(t, i + 1)) && r) { - D[r] = t - } - return t - } else { - if (t && r) { - D[l] = t + for (i in A) { + if (isarray(A[i])) { + if (! _printarrexp || i ~ _printarrexp) { + _printarr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") } } - return t } - - function _patharr0_i1(D, A, i, q, t, c) - { - if (D["type"] == "UNC") { - if (t = A[i++]) { - D[0] = (D["share"] = D[++c] = t) "/" - } else { - return 1 - } + if (! f) { + if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" } - while (i < q) { - D[0] = D[0] (D[++c] = A[i++]) "/" - } - if (i == q) { - if (match(t = A[i], /\.[^\.]*$/)) { - if (RSTART > 1) { - D["name"] = substr(t, 1, RSTART - 1) - } - D["ext"] = substr(t, RSTART, RLENGTH) + } +} + +function _qparam(qm, p0, p1, p2, p3, p4, p5, p6, p7) +{ + if (qm == qm + 0 && qm > 0) { + _qparamim = substr(" ", 1, qm) + } else { + if (qm != "") { + _qparamim = qm + } else { + _qparamim = " " + } + } + _qparamask = "" + return _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) +} + +function _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) +{ + _qparama0 = substr(_qparamim, 1, 1) + _qparamim = substr(_qparamim, 2) + switch (_qparama0) { + case "": + gsub(/ +$/, "", _qparamask) + return length(_qparamask) + default: + if (isarray(p0)) { + _qparama0 = "A" + } else { + if (p0 == "" && p0 == 0) { + _qparama0 = " " } else { - if (t != "") { - D["name"] = t + if (_isptr(p0)) { + _qparama0 = "P" + } else { + _qparama0 = "S" } } } - return 1 + case ".": + _qparamask = _qparamask _qparama0 + return _qparam_i0(p1, p2, p3, p4, p5, p6, p7) + } +} + +#_______________________________________________________________________ +function _qstr(t, c, A, B) +{ + ################################################ + c = "" + for (t = split(t, A, /[\x00-\x1F\\"]/, B); t >= 0; t--) { + c = _QSTR[B[t]] A[t + 1] c + } + return c +} + +#_________________________________________________________________ +function _qstrq(t) +{ + ################################################ + gsub(/\\/, "\\\\", t) + gsub(/"/, "\\\"", t) + return t +} + +################################################################ +#_____________________________________________________________________________ +function _rEG(c, t, P, a, A) +{ + ##################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return _ln("_reg 0.001") + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _pmap(m, s1, s2, s3, s4, s5, s6, s7, s8) - { - if (match(m, /^([^\(]+)\(([^\)]*)\)$/, _QMAP)) { - _qparamf1 = _QMAP[1] - _QMAP[0] = "r" (_qparamc1 = split(_QMAP[2], _QMAP, "")) - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8) +#_______________________________________________________________________ +function _rFBRO(p) +{ + ###################################################### + if (p) { + if (p in _tPARENT) { + return _tFCHLD[_tPARENT[p]] } + while (p in _tPREV) { + p = _tPREV[p] + } + return p } - - function _pr0(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1() - } - - function _pr1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1) - } - - function _pr2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2) + return p +} + +#_______________________________________________________________________ +function _rFCHLD(p) +{ + ##################################################### + if (p && p in _tFCHLD) { + return _tFCHLD[p] + } + return "" +} + +######################## p="", !v +#_______________________________________________________________________ +function _rLBRO(p) +{ + ###################################################### + if (p) { + if (p in _tPARENT) { + return _tLCHLD[_tPARENT[p]] + } + while (p in _tNEXT) { + p = _tNEXT[p] + } + return p } - - function _pr3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3) + return p +} + +######################## p="" +#_______________________________________________________________________ +function _rLCHLD(p) +{ + ##################################################### + if (p && p in _tLCHLD) { + return _tLCHLD[p] + } + return "" +} + +#_______________________________________________________________________ +function _rLINK(p) +{ + ###################################################### + return ((p in _tLINK ? _tLINK[p] : "")) +} + +######################## p="" +#_______________________________________________________________________ +function _rNEXT(p) +{ + ###################################################### + if (p && p in _tNEXT) { + return _tNEXT[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rPARENT(p) +{ + #################################################### + if (p && p in _tPARENT) { + return _tPARENT[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rPREV(p) +{ + ###################################################### + if (p && p in _tPREV) { + return _tPREV[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rQBRO(p, c, p1) +{ + ################################################ + if (p) { + if (p in _tPARENT) { + return _tQCHLD[_tPARENT[p]] + } + c = 1 + p1 = p + while (p1 in _tPREV) { + c++ + p1 = _tPREV[p1] + } + while (p in _tNEXT) { + c++ + p = _tNEXT[p] + } + return c } - - function _pr4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4) + return p +} + +######################## p="" +#_______________________________________________________________________ +function _rQCHLD(p) +{ + ##################################################### + if (p && p in _tQCHLD) { + return _tQCHLD[p] + } + return "" +} + +#___________________________________________________________________________________ +# EMMULATED FUNCTIONAL FIELDS ###################################################### + +#_____________________________________________________________________________ +function _rSQFIRST(g, p, A) +{ + ##################################################### + if (isarray(A)) { + return _rSQFIRSTA(g, p, A) + } + _SQTOPTR[g] = p + _SQSTACK[g][0] = 0 + return _rsqgetptr(g, p) +} + +#_________________________________________________________________ +function _rSQFIRSTA(g, p, A) +{ + ######################################## + _SQTOPTR[g] = p + _SQSTACK[g][0] = 0 + if ((p = _rsqgetptr(g, p)) in A) { + return p } + return _rSQNEXTA(g, p, A) +} - function _pr5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5) +#_______________________________________________________________________ +function _rSQNEXT(g, p, A) +{ + ################################################ + if (isarray(A)) { + return _rSQNEXTA(g, p, A) } + return _rsqnext_i0(g, p) +} - function _pr6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6) +#_________________________________________________________________ +function _rSQNEXTA(g, p, A) +{ + ######################################### + if (p == _SQTOPTR[g]) { + if (_SQSTACK[g][0] > 0) { + _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] + return _rSQNEXTA(g, _SQSTACK[g][_SQSTACK[g][0]--], A) + } + return } - - function _pr7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6, p7) + while (p in _tNEXT) { + if ((p = _rsqgetptr(g, _tNEXT[p])) in A) { + return p + } } + return ((p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], A) : "")) +} - function _pr8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6, p7, p8) - } +function _rconl(t) +{ + _rprt = _rprt _ln(t) +} - function _printarr(A, t, lv, r, a) - { - a = PROCINFO["sorted_in"] - PROCINFO["sorted_in"] = "_lengthsort" - _printarrexp = (r ? r : "") - if (isarray(A)) { - delete _DUMPARR - _dumparrc = _dumparrd = "" - _printarr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) - PROCINFO["sorted_in"] = a - return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") - } - } +function _rconline(t) +{ + _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1)) +} - function _printarr_i1(A, lv, ls, ln, t, t2, i, a, f) - { - t2 = _getchrln(" ", length(t)) - if (ln == lv) { - if (ls > 0) { - for (i in A) { - ++a - } - } else { - for (i in A) { - (isarray(A[i]) ? ++a : "") - } - } - if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - return - } - if (ls >= 0) { - for (i in A) { - if (! _printarrexp || i ~ _printarrexp) { - if (! isarray(A[i])) { - if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - } - } - } - } - for (i in A) { - if (isarray(A[i])) { - if (! _printarrexp || i ~ _printarrexp) { - _printarr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") +#___________________________________________________________ +function _rd_shortcut(D, f) +{ + if ((_shrtcutf0 = _filepath(f)) && _shortcut_nerr(_shrtcuta0 = _cmd(_shortcut_fpath " /A:Q /F:\"" _shrtcutf0 "\" 2>&1"), _shrtcutf0)) { + ERRNO = "" + split(_shrtcuta0, _SHRTCUTA0, /\x0D?\x0A/) + for (_shrtcuta0 in _SHRTCUTA0) { + for (f in _SHORTCUTRSTRUC) { + if (match(_SHRTCUTA0[_shrtcuta0], "^" f)) { + D[_SHORTCUTRSTRUC[f]] = substr(_SHRTCUTA0[_shrtcuta0], 1 + RLENGTH) } } } - if (! f) { - if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - } } + return ((ERRNO ? ERRNO = "read shortcut: " ERRNO : _NOP)) +} - function _qparam(qm, p0, p1, p2, p3, p4, p5, p6, p7) - { - if (qm == qm + 0 && qm > 0) { - _qparamim = substr(" ", 1, qm) - } else { - if (qm != "") { - _qparamim = qm +#_______________________________________________________________________ +function _rdfile(f, i, A) +{ + ################################################ + if ((f = _filerdne(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return + } + _fio_cmda = RS + RS = ".{1,}" + _fio_cmdb = BINMODE + BINMODE = "rw" + ERRNO = RT = _NUL + getline RS < f + BINMODE = _fio_cmdb + RS = _fio_cmda + if (ERRNO == "") { + close(f) + } + if (ERRNO == "") { + return RT + } + return (RT = _NOP) +} + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# fn _th0,_th1,_th2,_th3 +# USAGE: +# _th0(p1,p2,p3,p4) +# +# Each of this functions can have up to 4 parameters. +# _th0(p1,p2,p3,p4) return 1st parameter (p1) +# _th1(p1,p2,p3,p4) return 2nd parameter (p2) +# _th2(p1,p2,p3,p4) return 3rd parameter (p3) +# _th3(p1,p2,p3,p4) return 4th parameter (p4) +#_____________________________________________________________________________ +# fn _nop(p1,p2,p3,p4,p5,p6,p7,p8) +# USAGE: +# _nop() +# +# Does not do any action. No result returned. Up to 8 parameters. +#_____________________________________________________________________________ +# fn _exit(c) +# USAGE: +# _exit(code) +# +# This function do the same as GAWK-operator `exit code'. +#_____________________________________________________________________________ +# fn _getdate() +# fn _getime() +# fn _getsecond() +# fn _getsecondsync() +function _rdreg(D, p) +{ + ################################################################ + _rdregp0 = "reg query \"" p "\" /S /reg:64 2>NUL" + _rdregfld = _rdregkey = 0 + _rdregq0 = split(gensub(/[\x0D?\x0A]{2,}/, _CHR["EOL"], "G", _cmd(_rdregp0)), _RDREGA0, /\x0D?\x0A/) + while (_rdregq0 > 0) { + _rdreg_i0(D) + } + return (_rdregfld + _rdregkey) +} + +#___________________________________________________________ +function _rdreg_i0(D, A) +{ + while (_rdregq0 > 0) { + if (match(_rdregp0 = _RDREGA0[_rdregq0--], / (.*) REG_((SZ)|(DWORD)|(QWORD)|(BINARY)|(EXPAND_SZ)|(MULTI_SZ)) (.*)$/, A)) { + if (! _rdreg_i0(D)) { + ++_rdregfld + D[_rdregp0 A[1] "." _RDREGTYPE[A[2]]] = A[9] + return } else { - _qparamim = " " + break } - } - _qparamask = "" - return _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) - } - - function _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) - { - _qparama0 = substr(_qparamim, 1, 1) - _qparamim = substr(_qparamim, 2) - switch (_qparama0) { - case "": - gsub(/ +$/, "", _qparamask) - return length(_qparamask) - default: - if (isarray(p0)) { - _qparama0 = "A" - } else { - if (p0 == "" && p0 == 0) { - _qparama0 = " " - } else { - if (_isptr(p0)) { - _qparama0 = "P" - } else { - _qparama0 = "S" - } - } + } else { + if (_rdregp0 ~ /^HK/) { + ++_rdregkey + return D[_rdregp0 = _rdregp0 "\\"] } - case ".": - _qparamask = _qparamask _qparama0 - return _qparam_i0(p1, p2, p3, p4, p5, p6, p7) } } + return 1 +} - function _qstr(t, c, A, B) - { - c = "" - for (t = split(t, A, /[\x00-\x1F\\"]/, B); t >= 0; t--) { - c = _QSTR[B[t]] A[t + 1] c - } - return c - } +#_____________________________________________________________________________________________________ +###################################################################################################### - function _qstrq(t) - { - gsub(/\\/, "\\\\", t) - gsub(/"/, "\\\"", t) - return t - } - function _rEG(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_reg 0.001") - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } - function _rFBRO(p) - { - if (p) { - if (p in _tPARENT) { - return _tFCHLD[_tPARENT[p]] - } - while (p in _tPREV) { - p = _tPREV[p] - } - return p - } - return p - } - function _rFCHLD(p) - { - if (p && p in _tFCHLD) { - return _tFCHLD[p] - } - return "" - } - function _rLBRO(p) - { - if (p) { - if (p in _tPARENT) { - return _tLCHLD[_tPARENT[p]] - } - while (p in _tNEXT) { - p = _tNEXT[p] - } - return p - } - return p - } - function _rLCHLD(p) - { - if (p && p in _tLCHLD) { - return _tLCHLD[p] - } - return "" - } - function _rLINK(p) - { - return ((p in _tLINK ? _tLINK[p] : "")) - } - function _rNEXT(p) - { - if (p && p in _tNEXT) { - return _tNEXT[p] - } - return "" - } - function _rPARENT(p) - { - if (p && p in _tPARENT) { - return _tPARENT[p] - } - return "" - } - function _rPREV(p) - { - if (p && p in _tPREV) { - return _tPREV[p] - } - return "" - } - function _rQBRO(p, c, p1) - { - if (p) { - if (p in _tPARENT) { - return _tQCHLD[_tPARENT[p]] - } - c = 1 - p1 = p - while (p1 in _tPREV) { - c++ - p1 = _tPREV[p1] - } - while (p in _tNEXT) { - c++ - p = _tNEXT[p] - } - return c - } - return p - } - function _rQCHLD(p) - { - if (p && p in _tQCHLD) { - return _tQCHLD[p] - } - return "" - } - function _rSQFIRST(g, p, A) - { - if (isarray(A)) { - return _rSQFIRSTA(g, p, A) - } - _SQTOPTR[g] = p - _SQSTACK[g][0] = 0 - return _rsqgetptr(g, p) - } - function _rSQFIRSTA(g, p, A) - { - _SQTOPTR[g] = p - _SQSTACK[g][0] = 0 - if ((p = _rsqgetptr(g, p)) in A) { - return p - } - return _rSQNEXTA(g, p, A) - } - function _rSQNEXT(g, p, A) - { - if (isarray(A)) { - return _rSQNEXTA(g, p, A) - } - return _rsqnext_i0(g, p) - } - function _rSQNEXTA(g, p, A) - { - if (p == _SQTOPTR[g]) { - if (_SQSTACK[g][0] > 0) { - _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] - return _rSQNEXTA(g, _SQSTACK[g][_SQSTACK[g][0]--], A) - } - return - } - while (p in _tNEXT) { - if ((p = _rsqgetptr(g, _tNEXT[p])) in A) { - return p - } - } - return ((p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], A) : "")) - } - function _rconl(t) - { - _rprt = _rprt _ln(t) - } - function _rconline(t) - { - _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1)) - } - function _rd_shortcut(D, f) - { - if ((_shrtcutf0 = _filepath(f)) && _shortcut_nerr(_shrtcuta0 = _cmd(_shortcut_fpath " /A:Q /F:\"" _shrtcutf0 "\" 2>&1"), _shrtcutf0)) { - ERRNO = "" - split(_shrtcuta0, _SHRTCUTA0, /\x0D?\x0A/) - for (_shrtcuta0 in _SHRTCUTA0) { - for (f in _SHORTCUTRSTRUC) { - if (match(_SHRTCUTA0[_shrtcuta0], "^" f)) { - D[_SHORTCUTRSTRUC[f]] = substr(_SHRTCUTA0[_shrtcuta0], 1 + RLENGTH) - } - } - } - } - return ((ERRNO ? ERRNO = "read shortcut: " ERRNO : _NOP)) - } - function _rdfile(f, i, A) - { - if ((f = _filerdne(f)) == "" || _filene(f) == "") { - ERRNO = "Filename error" - return - } - _fio_cmda = RS - RS = ".{1,}" - _fio_cmdb = BINMODE - BINMODE = "rw" - ERRNO = RT = _NUL - getline RS < f - BINMODE = _fio_cmdb - RS = _fio_cmda - if (ERRNO == "") { - close(f) - } - if (ERRNO == "") { - return RT - } - return (RT = _NOP) - } - function _rdreg(D, p) - { - _rdregp0 = "reg query \"" p "\" /S /reg:64 2>NUL" - _rdregfld = _rdregkey = 0 - _rdregq0 = split(gensub(/[\x0D?\x0A]{2,}/, _CHR["EOL"], "G", _cmd(_rdregp0)), _RDREGA0, /\x0D?\x0A/) - while (_rdregq0 > 0) { - _rdreg_i0(D) - } - return (_rdregfld + _rdregkey) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +function _rdsafe(A, i, d) +{ + if (i in A) { + return A[i] } + return d +} - function _rdreg_i0(D, A) - { - while (_rdregq0 > 0) { - if (match(_rdregp0 = _RDREGA0[_rdregq0--], / (.*) REG_((SZ)|(DWORD)|(QWORD)|(BINARY)|(EXPAND_SZ)|(MULTI_SZ)) (.*)$/, A)) { - if (! _rdreg_i0(D)) { - ++_rdregfld - D[_rdregp0 A[1] "." _RDREGTYPE[A[2]]] = A[9] - return +#_______________________________________________________________________ +function _reg_check(p) +{ + _tframe("_reg_check_i0", p, p) +} + +#_______________________________________________ +function _reg_check_i0(p, pp, p1, p2) +{ + if (_[p]["TYPE"] == "defreg") { + if (_[p]["REGPATH"] in _REG) { + if ("VALUE" in _[p]) { + if (_[p]["VALUE"] == _REG[_[p]["REGPATH"]]) { + _creport(p, substr("OK: REGENTRY MATCH(==" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) } else { - break + _dllerr(p, substr("REGENTRY NOT MATCH(!=" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) } } else { - if (_rdregp0 ~ /^HK/) { - ++_rdregkey - return D[_rdregp0 = _rdregp0 "\\"] + if (_VAR[_[p]["REGPATH"]] == _REG[_[p]["REGPATH"]]) { + _creport(p, substr("OK: REGPATH MATCH(==" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + } else { + _dllerr(p, substr("REGPATH NOT MATCH(!=" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) } } + } else { + _dllerr(p, substr("REGPATH NOT FOUND: " _[p]["REGPATH"], 1, 126)) } - return 1 - } - - function _rdsafe(A, i, d) - { - if (i in A) { - return A[i] - } - return d } +} - function _reg_check(p) - { - _tframe("_reg_check_i0", p, p) - } +#_____________________________________________________ +function _registryinit() +{ + _registrytmpfile = _getmpfile() +} - function _reg_check_i0(p, pp, p1, p2) - { - if (_[p]["TYPE"] == "defreg") { - if (_[p]["REGPATH"] in _REG) { - if ("VALUE" in _[p]) { - if (_[p]["VALUE"] == _REG[_[p]["REGPATH"]]) { - _creport(p, substr("OK: REGENTRY MATCH(==" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) - } else { - _dllerr(p, substr("REGENTRY NOT MATCH(!=" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) - } +# _rdregfld : gvar - number of readed registry fields by _rdreg() +# _rdregkey : gvar - number of readed registry keys by _rdreg() +#_____________________________________________________________________________ +function _regpath0(D, i, s, q, S) +{ + ############################################ 0 # + if (i = _patharr0(S, i)) { + if ("name" in S) { + D["name"] = S["name"] + } + if ("ext" in S) { + D["ext"] = S["ext"] + } + s = ((toupper(s = (i in S ? S[i] : "")) in _REGPATH0REGDIR ? D[++q] = _REGPATH0REGDIR[toupper(s)] : (D[++q] = _REGPATH0REGDIR[""]) "\\" (D[++q] = s))) "\\" + while (++i in S) { + s = s (D[++q] = S[i]) "\\" + } + if (s != "") { + D[0] = s + } + IGNORECASE = 1 + D["hostdir"] = "\\\\" (D["host"] = ("host" in S && ("" == (i = S["host"]) || "." == i || "?" == i || "localhost" == i) ? ENVIRON["COMPUTERNAME"] : i)) "\\" s + IGNORECASE = 0 + } +} + +#_________________________________________________________________________________________ +function _report(p) +{ + ####################################################################### + _report_t0 = _reportparnt = "" + _report_i0(p) + _tframe("_report_i0", p) + return _report_t0 +} + +function _report_i0(p, p0, p1, p2) +{ + if (p in _tPARENT) { + if (_reportparnt != (_reportparnt = _tPARENT[p])) { + _report_t0 = _report_t0 _ln() _ln((z = "_ " _[_tPARENT[p]]["NAME"] " ") _getchrln("_", _CON_WIDTH - length(z) - 2)) _ln(_getchrln("#", _CON_WIDTH - 2)) _ln() + } + } + if ("ERROR" in _[p]) { + _report_t0 = _report_t0 _reporterr(p, _[p]["ERROR"]) + } + if ("REPORT" in _[p]) { + _report_t0 = _report_t0 _ln(_[p]["REPORT"]) + } +} + +#___________________________________________________________________________________ +function _reporterr(p, t3, pp, t, t2) +{ + t = "" + pp = p + do { + ("NAME" in _[pp] ? t = _[pp]["NAME"] ": " t : "") + } while (pp = _rPARENT(pp)) + if (match(t3, /\x00/)) { + return (substr(t3, 1, RSTART - 1) t substr(t3, RSTART + 1)) + } + return (t t3) +} + +#___________________________________________________________________________________ +#################################################################################### + + + + +#_______________________________________________________________________ +# _CHR array +# +# _CHR[ASC-code decimal number]=="char" +# +# Contains 256 elements. The index is the decimal number from 0-255. +# The value is the single character with ASC-code equivalent to index number: +# +# _CHR[97] =="a" - character with ASC-code 97 is `a' +# +# This array is useful if you want to get character using it's ASC-code +#_________________________________________________________________ +# _ASC array +# +# _ASC[char]==number: ASC-code of char +# +# Contains 256 elements. The index is the any single character with ASC-code \x00-\xFF. +# The value is the number equivalent of character's ASC-code: +# +# _ASC["A"] ==65 - ASC-code of character `A' is 65 +# +# This array is useful if you want to get ASC-code of the character. +#_________________________________________________________________ +# _QASC array +# +# _QASC[char]=="string: octal ASC-code of char in 3-digit octal format" +# +# Contains 256 elements. The index is the any single charcter with ASC-code \x00-\xFF. +# The value is the octal number equivalent of character's ASC-code in fixed-length - 3-digit - string: +# +# _QASC["!"] =="041" - ASC-code of character `!' is 33(decimal) == 41(in octal) +# _QASC["\x0D"] =="015" +# +# This array is useful when some type of string escape conversion is performed. It allows quickly get +# replace string for the characters that can be specified only by character code in result string: +# +# "\x0D" -> "\\015" +#_______________________________________________________________________ + + + + + + + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# fn _getchrln(ptt,len) +#_____________________________________________________________________________ +# fn _tabtospc(src,tabstep,xcoord) +#################################################################################### + +#_____________________________________________________________________________ +function _retarr(A, i, p, a, q) +{ + ################################################## + if (isarray(A)) { + i = (i == "" ? 0 : i + 0) + q = A[_ARRLEN] + 0 + if (i < q) { + return (p A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + } + } +} + +function _retarr_i0(A, q, i, a) +{ + if (i < q) { + return (A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + } + while (q < i) { + delete A[++q] + } + return a +} + +#_________________________________________________________________ +function _retarrd(A, v, i) +{ + ######################################### + if (1 in A) { + return (A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12] A[13] A[14] A[15] A[16] (((i = 17) in A ? _retarrd_i0(A, i) v : v))) + } + delete A + return v +} + +#_____________________________________________________ +function _retarrd_i0(A, i) +{ + if (i in A) { + return (A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] ((i in A ? _retarrd_i0(A, i) : ""))) + } + delete A +} + +#_______________________________________________________________________ +######################################################################## +#EXPERIMENTAL + +function _rexpfn(R, t, p) +{ + _REXPFN[""] = "" + while (t) { + t = _rxpfn(R, t, p) + } + return _REXPFN[""] +} + +function _rexpfnend(t) +{ + _REXPFN[""] = t +} + +#_____________________________________________________________________________ +function _rexpstr(r, i, c, A) +{ + ################################################### + c = split(r, A, "") + r = "" + for (i = 1; i <= c; i++) { + r = r _REXPSTR[A[i]] + } + return r +} + +#_____________________________________________________________________________ +function _rexpstr_i0(t, A, p0) +{ + return (_REXPSTR[t] = "\\" t) +} + +#___________________________________________________________ +function _rmtsharerr(h, t) +{ + gsub(/[\x0D\x0A]+/, "", t) + if (t ~ /^The command failed: 53/) { + ERRNO = "host not found: \\\\" h + } else { + ERRNO = t ": \\\\" h + } +} + +function _rpp(q, D, S) +{ + _conl() + _conline(q) + _conl() + _regpath0(D, q) + #_conl(_dumparr(D)) + + _conl(_ln("DEST:") _dumparr(D)) + _conl() + return q +} + +#_________________________________________________________________________________________ +function _rrdreg(DD, p, k, t, v, c, i, q, tT, A, B, C, D) +{ + ############################################# old; regedit + if (! _registrytmpfile) { + _registryinit() + } + _cmd("regedit /E \"" _registrytmpfile "\" \"" p "\" 2>&1") + q = patsplit(gensub(/[\x00\xFF\xFE]+/, "", "G", _rdfile(_registrytmpfile)), A, /\x0D?\x0A\[[^\]]+\]\x0D?\x0A/, B) + for (i = 1; i <= q; i++) { + p = gensub(/(^[ \t\x0D\x0A]*\[)|((\\)\\+)|(\][ \t\x0D\x0A]*$)/, "\\3", "G", A[i]) + DD[p "\\"] + delete C[split(B[i], C, /[\x0D\x0A]+/)] + for (c = 1; c in C; c++) { + tt = tt C[c] + if (gsub(/\\$/, "", tt)) { + continue + } + if (tt == "") { + continue + } + if (match(_th0(tt, tt = ""), /((^"(([^\\"]|\\.)*)")|(@))=(("(([^\\"]|\\.)*)")|(dword:([[:xdigit:]]{8}))|(hex(\(([27b])\))?:(.*)))$/, D)) { + if (D[7]) { + t = "STR" + v = _unstr(D[8]) } else { - if (_VAR[_[p]["REGPATH"]] == _REG[_[p]["REGPATH"]]) { - _creport(p, substr("OK: REGPATH MATCH(==" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + if (D[10]) { + t = "W32" + v = D[11] } else { - _dllerr(p, substr("REGPATH NOT MATCH(!=" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + v = D[15] + if (D[13]) { + switch (D[14]) { + case "2": + t = "XSZ" + break + case "7": + t = "MSZ" + break + default: + t = "W64" + } + } else { + t = "BIN" + } } } + DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] ((D[5] ? "(Default)" : ""))) "." t)] = v } else { - _dllerr(p, substr("REGPATH NOT FOUND: " _[p]["REGPATH"], 1, 126)) + _fatal("regedit: unknown output format(" c "): `" C[c] "'") } } } +} - function _registryinit() - { - _registrytmpfile = _getmpfile() - } - - function _regpath0(D, i, s, q, S) - { - if (i = _patharr0(S, i)) { - if ("name" in S) { - D["name"] = S["name"] - } - if ("ext" in S) { - D["ext"] = S["ext"] - } - s = ((toupper(s = (i in S ? S[i] : "")) in _REGPATH0REGDIR ? D[++q] = _REGPATH0REGDIR[toupper(s)] : (D[++q] = _REGPATH0REGDIR[""]) "\\" (D[++q] = s))) "\\" - while (++i in S) { - s = s (D[++q] = S[i]) "\\" - } - if (s != "") { - D[0] = s - } - IGNORECASE = 1 - D["hostdir"] = "\\\\" (D["host"] = ("host" in S && ("" == (i = S["host"]) || "." == i || "?" == i || "localhost" == i) ? ENVIRON["COMPUTERNAME"] : i)) "\\" s - IGNORECASE = 0 +#_________________________________________________________________ +function _rsqgetptr(g, p, A) +{ + if (p in _tLINK) { + _SQSTACK[g][++_SQSTACK[g][0]] = p + _SQSTACK[g][++_SQSTACK[g][0]] = _SQTOPTR[g] + while ((p = _tLINK[p]) in _tLINK) { + _con(".") } + _SQTOPTR[g] = p } - - function _report(p) - { - _report_t0 = _reportparnt = "" - _report_i0(p) - _tframe("_report_i0", p) - return _report_t0 - } - - function _report_i0(p, p0, p1, p2) - { - if (p in _tPARENT) { - if (_reportparnt != (_reportparnt = _tPARENT[p])) { - _report_t0 = _report_t0 _ln() _ln((z = "_ " _[_tPARENT[p]]["NAME"] " ") _getchrln("_", _CON_WIDTH - length(z) - 2)) _ln(_getchrln("#", _CON_WIDTH - 2)) _ln() - } - } - if ("ERROR" in _[p]) { - _report_t0 = _report_t0 _reporterr(p, _[p]["ERROR"]) - } - if ("REPORT" in _[p]) { - _report_t0 = _report_t0 _ln(_[p]["REPORT"]) - } + if (p in _tFCHLD) { + return _rsqgetptr(g, _tFCHLD[p]) } + return p +} - function _reporterr(p, t3, pp, t, t2) - { - t = "" - pp = p - do { - ("NAME" in _[pp] ? t = _[pp]["NAME"] ": " t : "") - } while (pp = _rPARENT(pp)) - if (match(t3, /\x00/)) { - return (substr(t3, 1, RSTART - 1) t substr(t3, RSTART + 1)) +#___________________________________________________________ +function _rsqnext_i0(g, p) +{ + if (p == _SQTOPTR[g]) { + if (_SQSTACK[g][0] > 0) { + _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] + return _rsqnext_i0(g, _SQSTACK[g][_SQSTACK[g][0]--]) } - return (t t3) + return } - - function _retarr(A, i, p, a, q) - { - if (isarray(A)) { - i = (i == "" ? 0 : i + 0) - q = A[_ARRLEN] + 0 - if (i < q) { - return (p A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + if (p in _tNEXT) { + return _rsqgetptr(g, _tNEXT[p]) + } + return _rsqnext_i0(g, _tPARENT[p]) +} + +function _rtn(v, A) +{ + _conl() + _conline(_val(v) " : " _val(A)) + _conl() + _rtn2(v, A) + _conl() +} + +function _rtn2(v, A, r, t) +{ + r = (isarray(A) ? _typa(v, A) : _typ(v)) + if ("`" > _t0 && _t0) { + _conl("ggggg") + } + t = ((r ? "TRUE" : "FALSE")) " / " ((r > 0 ? r ">0" : r "!>0")) " / " ((r + 0 > 0 ? r "+0>0" : r "+0!>0")) " / " ((r + 0 != r ? r "+0!=" r : r "+0==" r)) " / " ((r && "`" > r ? "'`'>" r " && " r : "!('`'>" r " && " r ")")) + _conl("`" r "' : " t) + return r +} + +function _rxpfn(R, t, p, i, f, A) +{ + for (i in R) { + if (match(t, i, A)) { + f = R[i] + if (t != (t = @f(A, substr(t, RLENGTH + 1), p))) { + return t } } } + return _rexpfnend(t) +} - function _retarr_i0(A, q, i, a) - { - if (i < q) { - return (A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) - } - while (q < i) { - delete A[++q] - } - return a +############################################################## +#_____________________________________________________________________________ +function _sHARE(c, t, P, a, A) +{ + ################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return _ln("_share 1.000") + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _retarrd(A, v, i) - { - if (1 in A) { - return (A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12] A[13] A[14] A[15] A[16] (((i = 17) in A ? _retarrd_i0(A, i) v : v))) - } - delete A - return v +################################################################ +#_____________________________________________________________________________ +function _sYS(c, t, P, a, A) +{ + ##################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _retarrd_i0(A, i) - { - if (i in A) { - return (A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] ((i in A ? _retarrd_i0(A, i) : ""))) - } - delete A - } +#_______________________________________________________________________ +function _serv_check(p) +{ + _tframe("_serv_check_i0", p, p) +} - function _rexpfn(R, t, p) - { - _REXPFN[""] = "" - while (t) { - t = _rxpfn(R, t, p) +#_______________________________________________ +function _serv_check_i0(p, p0, p1, p2, p3, i, q, c) +{ + if (_[p]["TYPE"] == "defsrv") { + i = IGNORECASE + IGNORECASE = 1 + if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) { + _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112)) + } else { + _dllerr(p, "service " _[p]["SERVNAME"] " not detected") } - return _REXPFN[""] } + IGNORECASE = i +} - function _rexpfnend(t) - { - _REXPFN[""] = t +#_______________________________________________________________________ +function _setarrsort(f, a) +{ + ############################################## + a = PROCINFO["sorted_in"] + if (! f) { + delete PROCINFO["sorted_in"] + } else { + PROCINFO["sorted_in"] = f } + return a +} - function _rexpstr(r, i, c, A) - { - c = split(r, A, "") - r = "" - for (i = 1; i <= c; i++) { - r = r _REXPSTR[A[i]] +#_______________________________________________________________________ +function _setmpath(p, a) +{ + ################################################ + ERRNO = "" + if (p && (a = _filerd(p))) { + if (_FILEIO_TMPRD) { + _FILEIO_TMPATHS[_FILEIO_TMPRD] } - return r + #if ( _filexist(a) ) _del(a) + #_cmd("rd " a " /S /Q 2>NUL"); _cmd("del " a " /Q 2>NUL") + return (_FILEIO_TMPRD = a) + } else { + return _warning("`" p "': cannot set temporary folder" ((ERRNO ? ": " ERRNO : ""))) } +} - function _rexpstr_i0(t, A, p0) - { - return (_REXPSTR[t] = "\\" t) - } +#_________________________________________________________________________________________ +########################################################################################## - function _rmtsharerr(h, t) - { - gsub(/[\x0D\x0A]+/, "", t) - if (t ~ /^The command failed: 53/) { - ERRNO = "host not found: \\\\" h - } else { - ERRNO = t ": \\\\" h - } - } - function _rpp(q, D, S) - { - _conl() - _conline(q) - _conl() - _regpath0(D, q) - _conl(_ln("DEST:") _dumparr(D)) - _conl() - return q - } - function _rrdreg(DD, p, k, t, v, c, i, q, tT, A, B, C, D) - { - if (! _registrytmpfile) { - _registryinit() - } - _cmd("regedit /E \"" _registrytmpfile "\" \"" p "\" 2>&1") - q = patsplit(gensub(/[\x00\xFF\xFE]+/, "", "G", _rdfile(_registrytmpfile)), A, /\x0D?\x0A\[[^\]]+\]\x0D?\x0A/, B) - for (i = 1; i <= q; i++) { - p = gensub(/(^[ \t\x0D\x0A]*\[)|((\\)\\+)|(\][ \t\x0D\x0A]*$)/, "\\3", "G", A[i]) - DD[p "\\"] - delete C[split(B[i], C, /[\x0D\x0A]+/)] - for (c = 1; c in C; c++) { - tt = tt C[c] - if (gsub(/\\$/, "", tt)) { - continue - } - if (tt == "") { - continue - } - if (match(_th0(tt, tt = ""), /((^"(([^\\"]|\\.)*)")|(@))=(("(([^\\"]|\\.)*)")|(dword:([[:xdigit:]]{8}))|(hex(\(([27b])\))?:(.*)))$/, D)) { - if (D[7]) { - t = "STR" - v = _unstr(D[8]) - } else { - if (D[10]) { - t = "W32" - v = D[11] - } else { - v = D[15] - if (D[13]) { - switch (D[14]) { - case "2": - t = "XSZ" - break - case "7": - t = "MSZ" - break - default: - t = "W64" - } - } else { - t = "BIN" - } - } - } - DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] ((D[5] ? "(Default)" : ""))) "." t)] = v - } else { - _fatal("regedit: unknown output format(" c "): `" C[c] "'") - } - } - } - } - function _rsqgetptr(g, p, A) - { - if (p in _tLINK) { - _SQSTACK[g][++_SQSTACK[g][0]] = p - _SQSTACK[g][++_SQSTACK[g][0]] = _SQTOPTR[g] - while ((p = _tLINK[p]) in _tLINK) { - _con(".") - } - _SQTOPTR[g] = p - } - if (p in _tFCHLD) { - return _rsqgetptr(g, _tFCHLD[p]) - } - return p - } - function _rsqnext_i0(g, p) - { - if (p == _SQTOPTR[g]) { - if (_SQSTACK[g][0] > 0) { - _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] - return _rsqnext_i0(g, _SQSTACK[g][_SQSTACK[g][0]--]) - } - return - } - if (p in _tNEXT) { - return _rsqgetptr(g, _tNEXT[p]) - } - return _rsqnext_i0(g, _tPARENT[p]) - } - function _rtn(v, A) - { - _conl() - _conline(_val(v) " : " _val(A)) - _conl() - _rtn2(v, A) - _conl() - } - function _rtn2(v, A, r, t) - { - r = (isarray(A) ? _typa(v, A) : _typ(v)) - if ("`" > _t0 && _t0) { - _conl("ggggg") - } - t = ((r ? "TRUE" : "FALSE")) " / " ((r > 0 ? r ">0" : r "!>0")) " / " ((r + 0 > 0 ? r "+0>0" : r "+0!>0")) " / " ((r + 0 != r ? r "+0!=" r : r "+0==" r)) " / " ((r && "`" > r ? "'`'>" r " && " r : "!('`'>" r " && " r ")")) - _conl("`" r "' : " t) - return r - } - function _rxpfn(R, t, p, i, f, A) - { - for (i in R) { - if (match(t, i, A)) { - f = R[i] - if (t != (t = @f(A, substr(t, RLENGTH + 1), p))) { - return t - } - } - } - return _rexpfnend(t) - } - function _sHARE(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_share 1.000") - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } - function _sYS(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return - case "_lib_BEGIN": - return - case "_lib_END": - return - } - } - function _serv_check(p) - { - _tframe("_serv_check_i0", p, p) - } - function _serv_check_i0(p, p0, p1, p2, p3, i, q, c) - { - if (_[p]["TYPE"] == "defsrv") { - i = IGNORECASE - IGNORECASE = 1 - if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) { - _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112)) - } else { - _dllerr(p, "service " _[p]["SERVNAME"] " not detected") - } - } - IGNORECASE = i - } - function _setarrsort(f, a) - { - a = PROCINFO["sorted_in"] - if (! f) { - delete PROCINFO["sorted_in"] - } else { - PROCINFO["sorted_in"] = f - } - return a - } - function _setmpath(p, a) - { - ERRNO = "" - if (p && (a = _filerd(p))) { - if (_FILEIO_TMPRD) { - _FILEIO_TMPATHS[_FILEIO_TMPRD] - } - return (_FILEIO_TMPRD = a) - } else { - return _warning("`" p "': cannot set temporary folder" ((ERRNO ? ": " ERRNO : ""))) - } - } - function _sharelist(D, h, q, c, l, A, B) - { - delete D - c = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) " 2>&1" - if (match(c = _cmd(c), /\x0AShare[^\x0A]*Remark/)) { - gsub(/(^[^-]*\x0D?\x0A-+\x0D?\x0A[ \t]*)|(\x0D?\x0AThe command completed successfully.*$)/, "", c) - l = RLENGTH - 7 - split(c, A, /([ \t]*\x0D?\x0A)+[ \t]*/) - for (c in A) { - if (match(A[c], /((([^ \t:]+[ \t]+)*[^ \t:]+)[ \t]+)([A-Za-z])[ \t]*:/, B) && ++q) { - D[B[2]] = (A[c] ~ /\.\.\.$/ ? _sharepath(h, B[2]) : gensub(/[ \t\\\/]*$/, "\\\\", 1, substr(A[c], 1 + B[1, "length"], l - B[1, "length"]))) - } + + + + + +function _sharelist(D, h, q, c, l, A, B) +{ + ################################################# + delete D + c = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) " 2>&1" + if (match(c = _cmd(c), /\x0AShare[^\x0A]*Remark/)) { + gsub(/(^[^-]*\x0D?\x0A-+\x0D?\x0A[ \t]*)|(\x0D?\x0AThe command completed successfully.*$)/, "", c) + l = RLENGTH - 7 + split(c, A, /([ \t]*\x0D?\x0A)+[ \t]*/) + for (c in A) { + if (match(A[c], /((([^ \t:]+[ \t]+)*[^ \t:]+)[ \t]+)([A-Za-z])[ \t]*:/, B) && ++q) { + D[B[2]] = (A[c] ~ /\.\.\.$/ ? _sharepath(h, B[2]) : gensub(/[ \t\\\/]*$/, "\\\\", 1, substr(A[c], 1 + B[1, "length"], l - B[1, "length"]))) } - return q } - return _rmtsharerr(h, c) + return q } + return _rmtsharerr(h, c) +} - function _sharepath(h, s, A) - { - s = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) "\\\"" s "\" 2>&1" - if (match(s = _cmd(s), /\x0APath[ \t]+([^\x0D\x0A]+)/, _SHAREPATHA0)) { - return gensub(/[ \t\\\/]*$/, "\\\\", 1, _SHAREPATHA0[1]) - } - return _rmtsharerr(h, s) +#_____________________________________________________________________________ +function _sharepath(h, s, A) +{ + ################################################### + s = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) "\\\"" s "\" 2>&1" + if (match(s = _cmd(s), /\x0APath[ \t]+([^\x0D\x0A]+)/, _SHAREPATHA0)) { + return gensub(/[ \t\\\/]*$/, "\\\\", 1, _SHAREPATHA0[1]) } + return _rmtsharerr(h, s) +} - function _shortcut(D, S) - { - if (isarray(D)) { - if (isarray(S)) { - _addarrmask(D, S, _SHORTCUTWSTRUC) +function _shortcut(D, S) +{ + ############################################################# + if (isarray(D)) { + if (isarray(S)) { + _addarrmask(D, S, _SHORTCUTWSTRUC) + } else { + if (S == 0 && S == "") { + # array,array2* - copy from array2 to array shorcut-specific elements + _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) } else { - if (S == 0 && S == "") { - _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) + if (_isnotfileptr(S)) { + # array* - define shortcut-specific elements in array by default values + _addarrmask(D, _[S], _SHORTCUTWSTRUC) } else { - if (_isnotfileptr(S)) { - _addarrmask(D, _[S], _SHORTCUTWSTRUC) - } else { - if (_rd_shortcut(D, S)) { - return - } + if (_rd_shortcut(D, S)) { + return } } } + } + # array,ptr* - copy from array _[ptr] to array shorcut-specific elements + } else { + if (D == 0 && D == "") { + return _NOP } else { - if (D == 0 && D == "") { - return _NOP - } else { - if (_isnotfileptr(D)) { - if (isarray(S)) { - _addarrmask(_[D], S, _SHORTCUTWSTRUC) + if (_isnotfileptr(D)) { + # -* - no action(return -) + if (isarray(S)) { + _addarrmask(_[D], S, _SHORTCUTWSTRUC) + } else { + if (S == 0 && S == "") { + # ptr,array* - copy from array to array _[ptr] shorcut-specific elements + _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) } else { - if (S == 0 && S == "") { - _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) + if (_isnotfileptr(S)) { + # ptr* - define shortcut-specifc elements in array _[ptr] by default values + _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) } else { - if (_isnotfileptr(S)) { - _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) - } else { - if (_rd_shortcut(_[D], S)) { - return - } + if (_rd_shortcut(_[D], S)) { + return } } } + } + # ptr,ptr2* - copy from array _[ptr2] to array _[ptr] shorcut-specific elements + } else { + # ptr,filepath* - define in array _[ptr] shortcut-specific elements by reading its from shortcut file filepath(load shortcut) + if (isarray(S) && _wr_shortcut(D, S)) { + return } else { - if (isarray(S) && _wr_shortcut(D, S)) { + if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) { return } else { - if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) { + if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) { return } else { - if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) { + if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) { return - } else { - if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) { - return - } } } } } - } - } - return 1 - } - - function _shortcut_init(A, B, q) - { - _SHORTCUTERR[2] = "file not found" - _SHORTCUTERR[3] = "no such filepath" - _SHORTCUTERR["The system cannot find the file specified."] = "no such filepath" - _SHORTCUTERR[5] = "file is folder" - _SHORTCUTERR["Access is denied."] = "file is folder" - _SHORTCUTERR[123] = "filepath syntax error" - _SHORTCUTERR["The filename, directory name, or volume label syntax is incorrect."] = "filepath syntax error" - q = "target\t\t\t/T:\t\t\t\tTargetPath=\t\t\t\t\ttarget?\t\t\t;\t\t\t_target\t\t\t\t\t\t\tTargetPathExpanded=\t\t\t\t\t\t\t;\t\t\tparameters\t\t\t/P:\t\t\t\tArguments=\t\t\t\t\tparaneters?\t\t\t;\t\t\t_parameters\t\t\t\t\t\t\tArgumentsExpanded=\t\t\t\t\t\t\t;\t\t\tstartdir\t\t\t/W:\t\t\t\tWorkingDirectory=\t\t\t\tstartdir?\t\t\t;\t\t\t_startdir\t\t\t\t\t\t\tWorkingDirectoryExpanded=\t\t\t\t\t\t;\t\t\trunstyle\t\t\t/R:\t\t\t\tRunStyle=\t\t\t\t\t1\t\t\t\t;\t\t\ticon,index\t\t\t/I:\t\t\t\tIconLocation=\t\t\t\ticon,index?\t\t\t;\t\t\txicon,index\t\t\t\t\t\t\tIconLocationExpanded=\t\t\t\t\t\t\t;\t\t\tshortcut key\t\t/H:\t\t\t\tHotKey=\t\t\t\t\t0\t\t\t\t;\t\t\tdescription\t\t\t/D:\t\t\t\tDescription=\t\t\t\t_env4: default shortcut\t" - split(q, _SHRTCUTA0, /[ \t]*;[ \t]*/) - for (q in _SHRTCUTA0) { - if (match(_SHRTCUTA0[q], /^([^\t]+)\t+([^\t]+)(\t+([^\t]+)(\t+([^\t]+))?)?/, B)) { - if (B[3] == "") { - _SHORTCUTRSTRUC[B[2]] = B[1] + # filepath,ptr* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array _[ptr](save shortcut) + } + } + } + # filepath,filepath2* - [over]write shorcut file filepath; shortcut parameters will be defined from shortcut file filepath2(copy shortcut) + return 1 +} + +#________________________________________________ +function _shortcut_init(A, B, q) +{ + _SHORTCUTERR[2] = "file not found" + _SHORTCUTERR[3] = "no such filepath" + _SHORTCUTERR["The system cannot find the file specified."] = "no such filepath" + _SHORTCUTERR[5] = "file is folder" + _SHORTCUTERR["Access is denied."] = "file is folder" + _SHORTCUTERR[123] = "filepath syntax error" + _SHORTCUTERR["The filename, directory name, or volume label syntax is incorrect."] = "filepath syntax error" + q = "target\t\t\t/T:\t\t\t\tTargetPath=\t\t\t\t\ttarget?\t\t\t;\t\t\t_target\t\t\t\t\t\t\tTargetPathExpanded=\t\t\t\t\t\t\t;\t\t\tparameters\t\t\t/P:\t\t\t\tArguments=\t\t\t\t\tparaneters?\t\t\t;\t\t\t_parameters\t\t\t\t\t\t\tArgumentsExpanded=\t\t\t\t\t\t\t;\t\t\tstartdir\t\t\t/W:\t\t\t\tWorkingDirectory=\t\t\t\tstartdir?\t\t\t;\t\t\t_startdir\t\t\t\t\t\t\tWorkingDirectoryExpanded=\t\t\t\t\t\t;\t\t\trunstyle\t\t\t/R:\t\t\t\tRunStyle=\t\t\t\t\t1\t\t\t\t;\t\t\ticon,index\t\t\t/I:\t\t\t\tIconLocation=\t\t\t\ticon,index?\t\t\t;\t\t\txicon,index\t\t\t\t\t\t\tIconLocationExpanded=\t\t\t\t\t\t\t;\t\t\tshortcut key\t\t/H:\t\t\t\tHotKey=\t\t\t\t\t0\t\t\t\t;\t\t\tdescription\t\t\t/D:\t\t\t\tDescription=\t\t\t\t_env4: default shortcut\t" + split(q, _SHRTCUTA0, /[ \t]*;[ \t]*/) + for (q in _SHRTCUTA0) { + if (match(_SHRTCUTA0[q], /^([^\t]+)\t+([^\t]+)(\t+([^\t]+)(\t+([^\t]+))?)?/, B)) { + if (B[3] == "") { + _SHORTCUTRSTRUC[B[2]] = B[1] + } else { + if (B[5] == "") { + _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] + delete _SHORTCUTDEFAULT[B[1]] } else { - if (B[5] == "") { - _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] - delete _SHORTCUTDEFAULT[B[1]] - } else { - _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] - _SHORTCUTDEFAULT[B[1]] = B[6] - } + _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] + _SHORTCUTDEFAULT[B[1]] = B[6] } - } else { - _fatal("_shortcut.init: _shortcut_struc: syntax error: `" _SHRTCUTA0[q] "'") } - } - _SHRTCUTA1[""] - delete _SHRTCUTA1[""] - _shortcut_fpath = "\\\\localhost\\eGAWK\\LIB\\_shortcut\\_shortcut.exe" - } - - function _shortcut_nerr(t, s, A) - { - if (match(t, /\x0ASystem error (-?[0-9]+)[^\x0D\x0A]*[\x0D\x0A]+([^\x0D\x0A]+)/, A)) { - ERRNO = ((A[1] in _SHORTCUTERR ? _SHORTCUTERR[A[1]] : (A[2] in _SHORTCUTERR ? _SHORTCUTERR[A[2]] : tolower(gensub(/^(The )?(((.*)\.$)|(.*[^\.]$))/, "\\4\\5", "G", A[2])) "(" A[1] ")"))) ((s ? ": `" s "'" : "")) } else { - return 1 + _fatal("_shortcut.init: _shortcut_struc: syntax error: `" _SHRTCUTA0[q] "'") } } + _SHRTCUTA1[""] + delete _SHRTCUTA1[""] + _shortcut_fpath = "\\\\localhost\\eGAWK\\LIB\\_shortcut\\_shortcut.exe" +} - function _split_regpath() - { - _rpp(" / / / / ") - _rpp(" / / / / huj ") - _rpp(" / / / / huj / ") - _rpp(" / / / / huj / pizda.TSR ") - _rpp(" / / / / hklm ") - _rpp(" / / / / hklm / ") - _rpp(" / / / / hklm / huj ") - _rpp(" / / / / hklm / huj / ") - _rpp(" / / / / hklm / huj / \tpizda.TSR ") - _conl() - _conl("########################################################################################") - _conl() - _rpp(" / / / / hklm / software / altiris / fi le . ex t ") - _rpp(" / / . / / hkcr / software / altiris / fi le . ex t ") - _rpp(" / / ? / / hKcU / software / altiris / fi le . ex t ") - _rpp(" / / lOcAlHoSt / / hKu / software / altiris / fi le . ex t ") - _rpp(" / / ho st / / hKcc / software / altiris / fi le . ex t ") - _rpp(" / / ho st / / hKPd / software / altiris / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - } - - function _splitpath_test() - { - _conl() - _conl("########################################################################################") - _conl() - _fpp(" ") - _fpp(" fi le . ex t ") - _fpp(" di r0 / / ") - _fpp(" di r0 / / fi le . ex t ") - _fpp(" / ") - _fpp(" / fi le . ex t ") - _fpp(" / di r0 / / ") - _fpp(" / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" c : ") - _fpp(" c : fi le . ex t ") - _fpp(" c : di r0 / / ") - _fpp(" c : di r0 / / fi le . ex t ") - _fpp(" c : / / ") - _fpp(" c : / / fi le . ex t ") - _fpp(" c : / / di r0 / / ") - _fpp(" c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / ") - _fpp(" / / ho st . hs t ") - _fpp(" / / ho st / / ") - _fpp(" / / ho st / / fi le . ex t ") - _fpp(" / / ho st / / di r0 / / ") - _fpp(" / / ho st / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / ho st / / c : ") - _fpp(" / / ho st / / c : fi le . ex t ") - _fpp(" / / ho st / / c : di r0 / / ") - _fpp(" / / ho st / / c : di r0 / / fi le . ex t ") - _fpp(" / / ho st / / c : / / ") - _fpp(" / / ho st / / c : / / fi le . ex t ") - _fpp(" / / ho st / / c : / / di r0 / / ") - _fpp(" / / ho st / / c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" http : / / / ") - _fpp(" http : / / / si te . ex t ") - _fpp(" http : / / / si te / / ") - _fpp(" http : / / / si te / / fi le . ex t ") - _fpp(" http : / / / si te / / di r0 / / ") - _fpp(" http : / / / si te / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" ftp : / / / : po rt ") - _fpp(" ftp : / / / si te . ex t : po rt ") - _fpp(" ftp : / / / si te : po rt / / ") - _fpp(" ftp : / / / si te : po rt / / fi le . ex t ") - _fpp(" ftp : / / / si te : po rt / / di r0 / / ") - _fpp(" ftp : / / / si te : po rt / / di r0 / / fi le . ex t ") - _conl() - _conl("## //. ######################################################################################") - _conl() - _fpp(" / / . ") - _fpp(" / / . / / ") - _fpp(" / / . / / com 56 ") - _fpp(" / / . / / com 56 / / ") - _fpp(" / / . / / c : ") - _fpp(" / / . / / c : / / ") - _fpp(" / / . / / c : com 56 ") - _fpp(" / / . / / c : com 56 / / ") - _fpp(" / / . / / c : / / com 56 ") - _fpp(" / / . / / c : / / com 56 / / ") - _conl() - _conl("## //? ######################################################################################") - _conl() - _fpp(" / / ? ") - _fpp(" / / ? / / ") - _fpp(" / / ? / / com 56 ") - _fpp(" / / ? / / com 56 / / ") - _fpp(" / / ? / / c : ") - _fpp(" / / ? / / c : / / ") - _fpp(" / / ? / / c : com 56 ") - _fpp(" / / ? / / c : com 56 / / ") - _fpp(" / / ? / / c : / / com 56 ") - _fpp(" / / ? / / c : / / com 56 / / ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / / ") - _fpp(" / / / . hs t ") - _fpp(" / / / / fi le . ex t ") - _fpp(" / / / / di r0 / / ") - _fpp(" / / / / di r0 / / di r1 / fi le . ex t ") - _fpp(" / / / / c : ") - _fpp(" / / / / c : fi le . ex t ") - _fpp(" / / / / c : di r0 / / ") - _fpp(" / / / / c : di r0 / / fi le . ex t ") - _fpp(" / / / / c : / / ") - _fpp(" / / / / c : / / fi le . ex t ") - _fpp(" / / / / c : / / di r0 / / ") - _fpp(" / / / / c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - return +#_____________________________________________________ +function _shortcut_nerr(t, s, A) +{ + if (match(t, /\x0ASystem error (-?[0-9]+)[^\x0D\x0A]*[\x0D\x0A]+([^\x0D\x0A]+)/, A)) { + ERRNO = ((A[1] in _SHORTCUTERR ? _SHORTCUTERR[A[1]] : (A[2] in _SHORTCUTERR ? _SHORTCUTERR[A[2]] : tolower(gensub(/^(The )?(((.*)\.$)|(.*[^\.]$))/, "\\4\\5", "G", A[2])) "(" A[1] ")"))) ((s ? ": `" s "'" : "")) + } else { + return 1 } - - function _splitstr(A, t, r) - { - if (_istr(t)) { - if (_splitstr_i0(A, t) > 0) { - return _splitstrp0 - } - if (_istr(r)) { - return _splitstr_i0(A, r) - } - } else { - if (it == "A") { - if (length(t) > 0) { - _movarr(A, t) - return (0 - length(A)) - } - } - _istr(r) - } +} + +function _split_regpath() +{ + _rpp(" / / / / ") + _rpp(" / / / / huj ") + _rpp(" / / / / huj / ") + _rpp(" / / / / huj / pizda.TSR ") + _rpp(" / / / / hklm ") + _rpp(" / / / / hklm / ") + _rpp(" / / / / hklm / huj ") + _rpp(" / / / / hklm / huj / ") + _rpp(" / / / / hklm / huj / \tpizda.TSR ") + _conl() + _conl("########################################################################################") + _conl() + _rpp(" / / / / hklm / software / altiris / fi le . ex t ") + _rpp(" / / . / / hkcr / software / altiris / fi le . ex t ") + _rpp(" / / ? / / hKcU / software / altiris / fi le . ex t ") + _rpp(" / / lOcAlHoSt / / hKu / software / altiris / fi le . ex t ") + _rpp(" / / ho st / / hKcc / software / altiris / fi le . ex t ") + _rpp(" / / ho st / / hKPd / software / altiris / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() +} + +function _splitpath_test() +{ + _conl() + _conl("########################################################################################") + _conl() + _fpp(" ") + _fpp(" fi le . ex t ") + _fpp(" di r0 / / ") + _fpp(" di r0 / / fi le . ex t ") + _fpp(" / ") + _fpp(" / fi le . ex t ") + _fpp(" / di r0 / / ") + _fpp(" / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" c : ") + _fpp(" c : fi le . ex t ") + _fpp(" c : di r0 / / ") + _fpp(" c : di r0 / / fi le . ex t ") + _fpp(" c : / / ") + _fpp(" c : / / fi le . ex t ") + _fpp(" c : / / di r0 / / ") + _fpp(" c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / ") + _fpp(" / / ho st . hs t ") + _fpp(" / / ho st / / ") + _fpp(" / / ho st / / fi le . ex t ") + _fpp(" / / ho st / / di r0 / / ") + _fpp(" / / ho st / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / ho st / / c : ") + _fpp(" / / ho st / / c : fi le . ex t ") + _fpp(" / / ho st / / c : di r0 / / ") + _fpp(" / / ho st / / c : di r0 / / fi le . ex t ") + _fpp(" / / ho st / / c : / / ") + _fpp(" / / ho st / / c : / / fi le . ex t ") + _fpp(" / / ho st / / c : / / di r0 / / ") + _fpp(" / / ho st / / c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" http : / / / ") + _fpp(" http : / / / si te . ex t ") + _fpp(" http : / / / si te / / ") + _fpp(" http : / / / si te / / fi le . ex t ") + _fpp(" http : / / / si te / / di r0 / / ") + _fpp(" http : / / / si te / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" ftp : / / / : po rt ") + _fpp(" ftp : / / / si te . ex t : po rt ") + _fpp(" ftp : / / / si te : po rt / / ") + _fpp(" ftp : / / / si te : po rt / / fi le . ex t ") + _fpp(" ftp : / / / si te : po rt / / di r0 / / ") + _fpp(" ftp : / / / si te : po rt / / di r0 / / fi le . ex t ") + _conl() + _conl("## //. ######################################################################################") + _conl() + _fpp(" / / . ") + _fpp(" / / . / / ") + _fpp(" / / . / / com 56 ") + _fpp(" / / . / / com 56 / / ") + _fpp(" / / . / / c : ") + _fpp(" / / . / / c : / / ") + _fpp(" / / . / / c : com 56 ") + _fpp(" / / . / / c : com 56 / / ") + _fpp(" / / . / / c : / / com 56 ") + _fpp(" / / . / / c : / / com 56 / / ") + _conl() + _conl("## //? ######################################################################################") + _conl() + _fpp(" / / ? ") + _fpp(" / / ? / / ") + _fpp(" / / ? / / com 56 ") + _fpp(" / / ? / / com 56 / / ") + _fpp(" / / ? / / c : ") + _fpp(" / / ? / / c : / / ") + _fpp(" / / ? / / c : com 56 ") + _fpp(" / / ? / / c : com 56 / / ") + _fpp(" / / ? / / c : / / com 56 ") + _fpp(" / / ? / / c : / / com 56 / / ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / / ") + _fpp(" / / / . hs t ") + _fpp(" / / / / fi le . ex t ") + _fpp(" / / / / di r0 / / ") + _fpp(" / / / / di r0 / / di r1 / fi le . ex t ") + _fpp(" / / / / c : ") + _fpp(" / / / / c : fi le . ex t ") + _fpp(" / / / / c : di r0 / / ") + _fpp(" / / / / c : di r0 / / fi le . ex t ") + _fpp(" / / / / c : / / ") + _fpp(" / / / / c : / / fi le . ex t ") + _fpp(" / / / / c : / / di r0 / / ") + _fpp(" / / / / c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + return +} + +#_______________________________________________________________________ +function _splitstr(A, t, r) +{ + ########################################### 1 # + if (_istr(t)) { + if (_splitstr_i0(A, t) > 0) { + return _splitstrp0 + } + if (_istr(r)) { + return _splitstr_i0(A, r) + } + } else { if (it == "A") { - if (length(r) > 0) { - _movarr(A, r) + if (length(t) > 0) { + _movarr(A, t) return (0 - length(A)) } } + _istr(r) } - - function _splitstr_i0(A, t, C) - { - if (2 > (_splitstrq0 = patsplit(t, _SPLITSTRA0, /([^,\xB4]*\xB4.)*[^,\xB4]*/))) { - _splitstrq0 = split(gensub(/\xB4(.)/, "\\1", "G", t), _SPLITSTRA0, "") + if (it == "A") { + if (length(r) > 0) { + _movarr(A, r) + return (0 - length(A)) } - delete A - _splitstri0 = _splitstrp0 = 0 - while (_splitstri0++ < _splitstrq0) { - if ((t = gensub(/\xB4(.)/, "\\1", "G", _SPLITSTRA0[_splitstri0])) in C || t == "") { - continue - } - C[A[++_splitstrp0] = t] - } - return _splitstrp0 } +} - function _strtorexp(t) - { - gsub(/[\\\.\?\*\+\-\(\)\{\}\[\]\^\$\/\|]/, "\\\\&", t) - t = split(t, _TOREXP_STRA, /[\x00-\x1F]/, _TOREXP_STRB) - _torexp_strt0 = "" - for (_torexp_stri0 = 1; _torexp_stri0 < t; _torexp_stri0++) { - _torexp_strt0 = _torexp_strt0 _TOREXP_STRA[_torexp_stri0] "\\" _QASC[_TOREXP_STRB[_torexp_stri0]] +#_____________________________________________________ +function _splitstr_i0(A, t, C) +{ + if (2 > (_splitstrq0 = patsplit(t, _SPLITSTRA0, /([^,\xB4]*\xB4.)*[^,\xB4]*/))) { + _splitstrq0 = split(gensub(/\xB4(.)/, "\\1", "G", t), _SPLITSTRA0, "") + } + delete A + _splitstri0 = _splitstrp0 = 0 + while (_splitstri0++ < _splitstrq0) { + if ((t = gensub(/\xB4(.)/, "\\1", "G", _SPLITSTRA0[_splitstri0])) in C || t == "") { + continue } - return (_torexp_strt0 _TOREXP_STRA[_torexp_stri0]) + C[A[++_splitstrp0] = t] } + return _splitstrp0 +} - function _subseqoff(r, B) - { - patsplit(r, B, /\x84[^\x94]*\x94/) - return gensub(/\x84[^\x94]*\x94/, "\204", "G", r) +#_______________________________________________ +function _strtorexp(t) +{ + gsub(/[\\\.\?\*\+\-\(\)\{\}\[\]\^\$\/\|]/, "\\\\&", t) + t = split(t, _TOREXP_STRA, /[\x00-\x1F]/, _TOREXP_STRB) + _torexp_strt0 = "" + for (_torexp_stri0 = 1; _torexp_stri0 < t; _torexp_stri0++) { + _torexp_strt0 = _torexp_strt0 _TOREXP_STRA[_torexp_stri0] "\\" _QASC[_TOREXP_STRB[_torexp_stri0]] } + return (_torexp_strt0 _TOREXP_STRA[_torexp_stri0]) +} - function _subseqon(B, r, F, f, s, e, q, i, A) - { - q = split(r, A, /\x84/) - r = "" - f = F[""] - for (i = 1; i < q; i++) { - s = substr(e = B[i], 2, 1) - s = (s in F ? F[s] : F[""]) - r = r (@f(A[i])) (@s(substr(e, 3, length(e) - 3))) - } - return (r (@f(A[i]))) - } +function _subseqoff(r, B) +{ + patsplit(r, B, /\x84[^\x94]*\x94/) + return gensub(/\x84[^\x94]*\x94/, "\204", "G", r) +} - function _sysinfo(D, h) - { - h = "wmic /NODE: \"" h "\" OS 2>NUL" - if (split(_cmd(h), _SYSINFOA0, /[\x0D\x0A]+/) == 3) { - _sysinfol0 = length(h = _SYSINFOA0[2]) + 1 - _sysinfoq0 = _sysinfoq1 = split(_SYSINFOA0[1], _SYSINFOA0, / +/, _SYSINFOB0) - while (--_sysinfoq0 > 0) { - D[_sysinfof0] = gensub(/^ +| +$/, "", "G", substr(h, _sysinfol0 = _sysinfol0 - (_sysinfol1 = length(_sysinfof0 = _SYSINFOA0[_sysinfoq0]) + length(_SYSINFOB0[_sysinfoq0])), _sysinfol1)) - } - return (_sysinfoq1 - 1) - } +function _subseqon(B, r, F, f, s, e, q, i, A) +{ + q = split(r, A, /\x84/) + r = "" + f = F[""] + for (i = 1; i < q; i++) { + s = substr(e = B[i], 2, 1) + #_conl("curr r==`" r "': A[" i "]=`" A[i] "'") + #s=s in F ? _th0(F[s],_conl("handler `" F[s] "' for `" s "' ost=`" substr(e,3,length(e)-3) "'")) : _th0(F[""],_conl("default handler for `" s "'")) + s = (s in F ? F[s] : F[""]) + #_conl("`" f "'") + r = r (@f(A[i])) (@s(substr(e, 3, length(e) - 3))) } + return (r (@f(A[i]))) +} - function _tOBJ(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - return t - case "_lib_APPLY": - return - case "_lib_HELP": - return - case "_lib_NAMEVER": - return _ln("_tOBJ 3.0") - case "_lib_BEGIN": - return - case "_lib_END": - return - case "_lib_CLEANUP": - return _tOBJ_CLEANUP() - } - } +#_____________________________________________________________________________ +# _rdreg(ARRAY,reg_path) +# Import into ARRAY the content of the whole registree tree with the higher point specified by reg_path. +# ARRAY will be filled by the strings with following format: +# +# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck\InstallPath.STR=C:\Program Files (x86)\GnuWin32 +# where: +# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck <- REG KEY PATH +# InstallPath <- DATA FIELD +# STR <- TYPE +# C:\Program Files (x86)\GnuWin32 <- VALUE +# TYPE: +# STR - REG_SZ (String Value) +# W32 - REG_DWORD (DWORD (32-bit) Value) +# W64 - REG_QWORD (QWORD (64-bit) Value) +# BIN - REG_BINARY (Binary Value) +# XSZ - REG_EXPAND_SZ (Expandable String Value) +# MSZ - REG_MULTI_SZ (Multi-String Value) +#_________________________________________________________________________________________ - function _tOBJ_CLEANUP(p) - { - for (p in UIDSDEL) { - delete _ptr[p] - delete _tPREV[p] - delete _tPARENT[p] - delete _tNEXT[p] - delete _tFCHLD[p] - delete _tQCHLD[p] - delete _tLCHLD[p] - delete _TMP0[p] - delete _TMP1[p] - delete _tLINK[p] - delete _tCLASS[p] - } - } - function _tabtospc(t, ts, xc, a, c, n, A, B) - { - if (! ts) { - ts = _TAB_STEP_DEFAULT - } - c = split("." t, A, /\t+/, B) - A[1] = substr(A[1], 2) - t = "" - for (n = 1; n <= c; n++) { - t = t A[n] _getchrln(" ", (xc = length(B[n]) * ts + int((a = xc + length(A[n])) / ts) * ts) - a) - } - return t - } - function _tapi(p, f, p0, p1, p2, p3, c) - { - c = p - do { - if (f in _[c]["API"]) { - f = _[c]["API"][f] - return @f(p, p0, p1, p2, p3) - } - c = _[c]["CLASS"] - } while ("CLASS" in _[c]) - } - function _tbframe(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbframe_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } +# HKCR HKEY_CLASSES_ROOT +# HKCU HKEY_CURRENT_USER +# HKLM HKEY_LOCAL_MACHINE +# HKU HKEY_USERS +# HKCC HKEY_CURRENT_CONFIG +# HKPD HKEY_PERFORMANCE_DATA - function _tbframe_i0(f, p, p0, p1, a) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbframe(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbframex(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbframex_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbframex_i0(f, p, p0, p1) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbframex(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbpass(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbpass_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbpass_i0(f, p, p0, p1, a) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbpass(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbpassx(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbpassx_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbpassx_i0(f, p, p0, p1) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbpassx(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbrochld(p, f, pp) - { - if (p) { - if (p in _tFCHLD) { - f = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - if (p in _tPARENT) { - pp = _tPARENT[p] - delete _tPARENT[p] - if (p in _tPREV) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f - delete _tPREV[p] - } else { - _tFCHLD[pp] = f - } - for (; f in _tNEXT; f = _tNEXT[f]) { - _tPARENT[f] = pp - } - _tPARENT[f] = pp - if (p in _tNEXT) { - _tPREV[_tNEXT[f] = _tNEXT[p]] = f - delete _tNEXT[p] - } else { - _tLCHLD[pp] = f - } - _tQCHLD[pp] = _tQCHLD[pp] + _tQCHLD[p] - 1 - delete _tQCHLD[p] - return f - } else { - delete _tQCHLD[p] - if (p in _tPREV) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f - delete _tPREV[p] - } - for (; f in _tNEXT; f = _tNEXT[f]) { - delete _tPARENT[f] - } - delete _tPARENT[f] - if (p in _tNEXT) { - _tPREV[_tNEXT[f] = _tNEXT[p]] = f - delete _tNEXT[p] - } - return f - } - } else { - if (p in _tPARENT) { - pp = _tPARENT[p] - delete _tPARENT[p] - if (p in _tPREV) { - if (p in _tNEXT) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] - delete _tNEXT[p] - } else { - delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] - } - delete _tPREV[p] - _tQCHLD[pp]-- - } else { - if (p in _tNEXT) { - delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] - delete _tNEXT[p] - _tQCHLD[pp]-- - } else { - delete _tFCHLD[pp] - delete _tLCHLD[pp] - delete _tQCHLD[pp] - } - } - } else { - if (p in _tPREV) { - if (p in _tNEXT) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] - delete _tNEXT[p] - } else { - delete _tNEXT[_tPREV[p]] - } - delete _tPREV[p] - } else { - if (p in _tNEXT) { - delete _tPREV[_tNEXT[p]] - delete _tNEXT[p] - } - } - } - } - } - return p - } - function _tbrunframe(f, p, p0, p1) - { - return _tbframe((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunframex(f, p, p0, p1) - { - return _tbframex((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunpass(f, p, p0, p1) - { - return _tbpass((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunpassx(f, p, p0, p1) - { - return _tbpassx((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tdel(p, i) - { - if (p in _) { - _texclude(p) - for (i in _ptr[p]) { - if (isarray(_ptr[p][i])) { - _tdel_i1(_ptr[p][i]) - } else { - if (i = _ptr[p][i]) { - _tdel(i) - } - } - } - if (p in _tFCHLD) { - i = _tFCHLD[p] - do { - i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) - } while (i) - } - delete _[p] - _UIDSDEL[p] - } - } - function _tdel_i0(p, i) - { - for (i in _ptr[p]) { - if (isarray(_ptr[p][i])) { - _tdel_i1(_ptr[p][i]) - } else { - if (i = _ptr[p][i]) { - _tdel(i) - } - } - } - if (p in _tFCHLD) { - i = _tFCHLD[p] - do { - i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) - } while (i) - } - delete _[p] - _UIDSDEL[p] - } - function _tdel_i1(A, i) - { - for (i in A) { - if (isarray(A[i])) { - _tdel_i1(A[i]) - } else { - if (i = A[i]) { - _tdel(i) - } - } - } - } - function _tdelete(p, v) - { - if (p) { - _wLCHLD(_tDELPTR, p) - } - return v - } - function _tdelitem(p) - { - if (p) { - if ("HOST" in _PTR[p] && "ITEMNAME" in _[p]) { - return _wLCHLD(_PTR[_PTR[p]["HOST"]]["ITEM"][_[p]["ITEMNAME"]], p) - } - _tdelete(p) - return p - } - } - function _tend(a, b) - { - if (b == "") { - return (_t_ENDF[_t_ENDF[0]] = a) - } else { - return (_t_ENDF[_t_ENDF[0] + a] = b) + + + + + + + + + + + + + + + + + + + + + + + + + + +#___________________________________________________________________________________ +#################################################################################### + + + + + + + + + + + + + + + + + + + + + + + +function _sysinfo(D, h) +{ + ############################################################## + h = "wmic /NODE: \"" h "\" OS 2>NUL" + if (split(_cmd(h), _SYSINFOA0, /[\x0D\x0A]+/) == 3) { + _sysinfol0 = length(h = _SYSINFOA0[2]) + 1 + _sysinfoq0 = _sysinfoq1 = split(_SYSINFOA0[1], _SYSINFOA0, / +/, _SYSINFOB0) + while (--_sysinfoq0 > 0) { + D[_sysinfof0] = gensub(/^ +| +$/, "", "G", substr(h, _sysinfol0 = _sysinfol0 - (_sysinfol1 = length(_sysinfof0 = _SYSINFOA0[_sysinfoq0]) + length(_SYSINFOB0[_sysinfoq0])), _sysinfol1)) } + return (_sysinfoq1 - 1) } +} - function _texclude(p, v, pp) - { - if (p in _) { +######################################################### + +function _tOBJ(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #___________________________________________________________ + case "_lib_APPLY": + return + #___________________________________________________________ + case "_lib_HELP": + return + #___________________________________________________________ + case "_lib_NAMEVER": + return _ln("_tOBJ 3.0") + #___________________________________________________________ + case "_lib_BEGIN": + return + #___________________________________________________________ + case "_lib_END": + return + #___________________________________________________________ + case "_lib_CLEANUP": + return _tOBJ_CLEANUP() + } +} + +#_______________________________________________________________________ +function _tOBJ_CLEANUP(p) +{ + ############################################## + for (p in UIDSDEL) { + delete _ptr[p] + delete _tPREV[p] + delete _tPARENT[p] + delete _tNEXT[p] + delete _tFCHLD[p] + delete _tQCHLD[p] + delete _tLCHLD[p] + delete _TMP0[p] + delete _TMP1[p] + delete _tLINK[p] + delete _tCLASS[p] + } +} + +#_______________________________________________________________________ +function _tabtospc(t, ts, xc, a, c, n, A, B) +{ + ################################## + if (! ts) { + ts = _TAB_STEP_DEFAULT + } + c = split("." t, A, /\t+/, B) + A[1] = substr(A[1], 2) + t = "" + for (n = 1; n <= c; n++) { + t = t A[n] _getchrln(" ", (xc = length(B[n]) * ts + int((a = xc + length(A[n])) / ts) * ts) - a) + } + return t +} + +#___________________________________________________________________________________ +#################################################################################### + + + + + + + +function _tapi(p, f, p0, p1, p2, p3, c) +{ + c = p + do { + if (f in _[c]["API"]) { + f = _[c]["API"][f] + return @f(p, p0, p1, p2, p3) + } + c = _[c]["CLASS"] + } while ("CLASS" in _[c]) +} + +#_____________________________________________________________________________ +function _tbframe(f, p, p0, p1) +{ + ################################################## + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbframe_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbframe_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbframe(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_______________________________________________________________________ +function _tbframex(f, p, p0, p1) +{ + ########################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbframex_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbframex_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbframex(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbpass(f, p, p0, p1) +{ + ################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbpass_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbpass_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbpass(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbpassx(f, p, p0, p1) +{ + ################################################## + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbpassx_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbpassx_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbpassx(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbrochld(p, f, pp) +{ + ################################################### # TEST!!! + if (p) { + if (p in _tFCHLD) { + f = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + if (p in _tPARENT) { + pp = _tPARENT[p] + delete _tPARENT[p] + if (p in _tPREV) { + _tNEXT[_tPREV[f] = _tPREV[p]] = f + delete _tPREV[p] + } else { + _tFCHLD[pp] = f + } + for (; f in _tNEXT; f = _tNEXT[f]) { + _tPARENT[f] = pp + } + _tPARENT[f] = pp + if (p in _tNEXT) { + _tPREV[_tNEXT[f] = _tNEXT[p]] = f + delete _tNEXT[p] + } else { + _tLCHLD[pp] = f + } + _tQCHLD[pp] = _tQCHLD[pp] + _tQCHLD[p] - 1 + delete _tQCHLD[p] + return f + } else { + delete _tQCHLD[p] + if (p in _tPREV) { + _tNEXT[_tPREV[f] = _tPREV[p]] = f + delete _tPREV[p] + } + for (; f in _tNEXT; f = _tNEXT[f]) { + delete _tPARENT[f] + } + delete _tPARENT[f] + if (p in _tNEXT) { + _tPREV[_tNEXT[f] = _tNEXT[p]] = f + delete _tNEXT[p] + } + return f + } + } else { if (p in _tPARENT) { pp = _tPARENT[p] delete _tPARENT[p] if (p in _tPREV) { if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] delete _tNEXT[p] } else { delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] } delete _tPREV[p] + _tQCHLD[pp]-- } else { if (p in _tNEXT) { delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] delete _tNEXT[p] + _tQCHLD[pp]-- } else { delete _tFCHLD[pp] delete _tLCHLD[pp] delete _tQCHLD[pp] - return p } } - --_tQCHLD[pp] } else { if (p in _tPREV) { if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] delete _tNEXT[p] } else { delete _tNEXT[_tPREV[p]] @@ -4777,1133 +5735,1521 @@ } } } - return p - } - } - - function _tframe(fF, p, p0, p1, p2) - { - delete _t_ENDF[++_t_ENDF[0]] - p = (_isptr(p) ? (isarray(fF) ? _tframe_i1(fF, p, p0, p1, p2) : _tframe_i0(fF, p, p0, p1, p2)) : "") - --_t_ENDF[0] - return p - } - - function _tframe0(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - if (isarray(f)) { - return _tframe0_i0(f, p) - } - _tframex_p0(A, f, 0) - return _th0(_tframe0_i0(A, p), --_TEND[_ARRLEN]) } } - - function _tframe0_i0(A, p, f) - { - if (p in _tLINK) { - _tframe_link = p - if ("`" in A) { - f = A["`"] - while (p in _tLINK) { - @f(p = _tLINK[p]) - } + return p +} + +#_________________________________________________________________ +function _tbrunframe(f, p, p0, p1) +{ + ################################### + return _tbframe((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunframex(f, p, p0, p1) +{ + ################################## + return _tbframex((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunpass(f, p, p0, p1) +{ + #################################### + return _tbpass((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunpassx(f, p, p0, p1) +{ + ################################### + return _tbpassx((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_____________________________________________________________________________ +function _tdel(p, i) +{ + ########################################################## + if (p in _) { + _texclude(p) + for (i in _ptr[p]) { + if (isarray(_ptr[p][i])) { + _tdel_i1(_ptr[p][i]) } else { - while (p in _tLINK) { - p = _tLINK[p] + if (i = _ptr[p][i]) { + _tdel(i) } } - } else { - _tframe_link = "" } if (p in _tFCHLD) { - return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p])) + i = _tFCHLD[p] + do { + i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) + } while (i) } - return _tframe0_i2(A, ".", p) + delete _[p] + _UIDSDEL[p] } +} - function _tframe0_i1(A, p) - { - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe0_i0(A, p) _tframe0_i1(A, _tNEXT[p])) +#_____________________________________________________ +function _tdel_i0(p, i) +{ + for (i in _ptr[p]) { + if (isarray(_ptr[p][i])) { + _tdel_i1(_ptr[p][i]) + } else { + if (i = _ptr[p][i]) { + _tdel(i) + } } - return _tframe0_i0(A, p) } - - function _tframe0_i2(A, m, p) - { - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } + if (p in _tFCHLD) { + i = _tFCHLD[p] + do { + i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) + } while (i) + } + delete _[p] + _UIDSDEL[p] +} + +#_____________________________________________________ +function _tdel_i1(A, i) +{ + for (i in A) { + if (isarray(A[i])) { + _tdel_i1(A[i]) + } else { + if (i = A[i]) { + _tdel(i) } - m = A[m] - return @m(p) } } +} - function _tframe1(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - if (isarray(f)) { - return _tframe1_i0(f, p, p0) - } - _tframex_p0(A, f, 1) - return _th0(_tframe1_i0(A, p, p0), --_TEND[_ARRLEN]) - } +#_____________________________________________________________________________ +function _tdelete(p, v) +{ + ####################################################### # REMAKE EXCLUDE + if (p) { + _wLCHLD(_tDELPTR, p) } + return v +} - function _tframe1_i0(A, p, p0) - { - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] +#_________________________________________________________________ +function _tdelitem(p) +{ + ############################################# + if (p) { + if ("HOST" in _PTR[p] && "ITEMNAME" in _[p]) { + return _wLCHLD(_PTR[_PTR[p]["HOST"]]["ITEM"][_[p]["ITEMNAME"]], p) } - if (p in _tFCHLD) { - return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0)) - } - return _tframe1_i2(A, ".", p, p0) + _tdelete(p) + return p } +} - function _tframe1_i1(A, p, p0) - { - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe1_i0(A, p, p0) _tframe1_i1(A, _tNEXT[p], p0)) - } - return _tframe1_i0(A, p, p0) +#_______________________________________________________________________ +function _tend(a, b) +{ + ##################################################### + if (b == "") { + return (_t_ENDF[_t_ENDF[0]] = a) + } else { + return (_t_ENDF[_t_ENDF[0] + a] = b) } +} - function _tframe1_i2(A, m, p, p0) - { - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return +#_____________________________________________________________________________ +function _texclude(p, v, pp) +{ + ################################################### # TEST!!! + if (p in _) { + if (p in _tPARENT) { + pp = _tPARENT[p] + delete _tPARENT[p] + if (p in _tPREV) { + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + delete _tNEXT[p] + } else { + delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] + } + delete _tPREV[p] + } else { + if (p in _tNEXT) { + delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] + delete _tNEXT[p] + } else { + delete _tFCHLD[pp] + delete _tLCHLD[pp] + delete _tQCHLD[pp] + return p } } - m = A[m] - return @m(p, p0) - } - } - - function _tframe2(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - if (isarray(f)) { - return _tframe2_i0(f, p, p0, p1) + --_tQCHLD[pp] + } else { + if (p in _tPREV) { + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + delete _tNEXT[p] + } else { + delete _tNEXT[_tPREV[p]] + } + delete _tPREV[p] + } else { + if (p in _tNEXT) { + delete _tPREV[_tNEXT[p]] + delete _tNEXT[p] + } } - _tframex_p0(A, f, 2) - return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN]) } + return p } - - function _tframe2_i0(A, p, p0, p1) - { +} + +# _tDLINK progressive development: concrete _tDLINK function\processing algo; all frame's families support +#_____________________________________________________________________________ +function _tframe(fF, p, p0, p1, p2) +{ + ############################################### + delete _t_ENDF[++_t_ENDF[0]] + p = (_isptr(p) ? (isarray(fF) ? _tframe_i1(fF, p, p0, p1, p2) : _tframe_i0(fF, p, p0, p1, p2)) : "") + --_t_ENDF[0] + return p +} + +#_____________________________________________________________________________ +function _tframe0(f, p, p0, p1, p2, p3, A) +{ + ######################################### + if (_isptr(p)) { + if (isarray(f)) { + return _tframe0_i0(f, p) + } + _tframex_p0(A, f, 0) + return _th0(_tframe0_i0(A, p), --_TEND[_ARRLEN]) + } +} + +#_______________________________________________ +function _tframe0_i0(A, p, f) +{ + if (p in _tLINK) { _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] - } - if (p in _tFCHLD) { - return (_tframe2_i2(A, "^", p, p0, p1) _tframe2_i1(A, _tFCHLD[p], p0, p1)) + if ("`" in A) { + f = A["`"] + while (p in _tLINK) { + @f(p = _tLINK[p]) + } + } else { + while (p in _tLINK) { + p = _tLINK[p] + } } - return _tframe2_i2(A, ".", p, p0, p1) + } else { + _tframe_link = "" } - - function _tframe2_i1(A, p, p0, p1) - { - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe2_i0(A, p, p0, p1) _tframe2_i1(A, _tNEXT[p], p0, p1)) - } - return _tframe2_i0(A, p, p0, p1) + if (p in _tFCHLD) { + return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p])) } + return _tframe0_i2(A, ".", p) +} - function _tframe2_i2(A, m, p, p0, p1) - { - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } - } - m = A[m] - return @m(p, p0, p1) - } +#_______________________________________________ +function _tframe0_i1(A, p) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } + if (p in _tNEXT) { + return (_tframe0_i0(A, p) _tframe0_i1(A, _tNEXT[p])) + } + return _tframe0_i0(A, p) +} - function _tframe3(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - if (isarray(f)) { - return _tframe3_i0(f, p, p0, p1, p2) +#_______________________________________________ +function _tframe0_i2(A, m, p) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] + } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - _tframex_p0(A, f, 3) - return _th0(_tframe3_i0(A, p, p0, p1, p2), --_TEND[_ARRLEN]) } + m = A[m] + return @m(p) } +} - function _tframe3_i0(A, p, p0, p1, p2) - { - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] - } - if (p in _tFCHLD) { - return (_tframe3_i2(A, "^", p, p0, p1, p2) _tframe3_i1(A, _tFCHLD[p], p0, p1, p2)) +#_________________________________________________________________ +function _tframe1(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe1_i0(f, p, p0) } - return _tframe3_i2(A, ".", p, p0, p1, p2) + _tframex_p0(A, f, 1) + return _th0(_tframe1_i0(A, p, p0), --_TEND[_ARRLEN]) } +} - function _tframe3_i1(A, p, p0, p1, p2) - { - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe3_i0(A, p, p0, p1, p2) _tframe3_i1(A, _tNEXT[p], p0, p1, p2)) - } - return _tframe3_i0(A, p, p0, p1, p2) +#_______________________________________________ +function _tframe1_i0(A, p, p0) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _tframe3_i2(A, m, p, p0, p1, p2) - { - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } - } - m = A[m] - return @m(p, p0, p1, p2) - } + if (p in _tFCHLD) { + return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0)) } + return _tframe1_i2(A, ".", p, p0) +} - function _tframe4(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - if (isarray(f)) { - return _tframe4_i0(f, p, p0, p1, p2, p3) - } - _tframex_p0(A, f, 4) - return _th0(_tframe4_i0(A, p, p0, p1, p2, p3), --_TEND[_ARRLEN]) - } +#_______________________________________________ +function _tframe1_i1(A, p, p0) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } - - function _tframe4_i0(A, p, p0, p1, p2, p3) - { - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] - } - if (p in _tFCHLD) { - return (_tframe4_i2(A, "^", p, p0, p1, p2, p3) _tframe4_i1(A, _tFCHLD[p], p0, p1, p2, p3)) - } - return _tframe4_i2(A, ".", p, p0, p1, p2, p3) + if (p in _tNEXT) { + return (_tframe1_i0(A, p, p0) _tframe1_i1(A, _tNEXT[p], p0)) } + return _tframe1_i0(A, p, p0) +} - function _tframe4_i1(A, p, p0, p1, p2, p3) - { - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe4_i0(A, p, p0, p1, p2, p3) _tframe4_i1(A, _tNEXT[p], p0, p1, p2, p3)) - } - return _tframe4_i0(A, p, p0, p1, p2, p3) +#_______________________________________________ +function _tframe1_i2(A, m, p, p0) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tframe4_i2(A, m, p, p0, p1, p2, p3) - { - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - m = A[m] - return @m(p, p0, p1, p2, p3) - } - } - - function _tframe_i0(f, p, p0, p1, p2, a) - { - while (p in _tLINK) { - p = _tLINK[p] } - return ((p in _tFCHLD ? _tmframe_i0(f, _tFCHLD[p], p0, p1, p2) : (p in _tDLINK ? @f(_tDLINK[p], p0, p1, p2) : @f(p, p0, p1, p2)))) + m = A[m] + return @m(p, p0) } +} - function _tframe_i1(F, p, p0, p1, p2, a) - { - while (p in _tLINK) { - p = _tLINK[p] +#_________________________________________________________________ +function _tframe2(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe2_i0(f, p, p0, p1) } - return ((p in _tFCHLD ? (("." in F ? _th1(a = F["."], @a(p, p0, p1, p2)) : "")) _tmframe_i1(F, _tFCHLD[p], p0, p1, p2) : (">" in F ? _th1(a = F[">"], (p in _tDLINK ? @a(_tDLINK[p], p0, p1, p2) : @a(p, p0, p1, p2))) : ""))) + _tframex_p0(A, f, 2) + return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN]) } +} - function _tframex(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tframex_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f +#_______________________________________________ +function _tframe2_i0(A, p, p0, p1) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _tframex_i0(f, p, p0, p1) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmframex(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) + if (p in _tFCHLD) { + return (_tframe2_i2(A, "^", p, p0, p1) _tframe2_i1(A, _tFCHLD[p], p0, p1)) } + return _tframe2_i2(A, ".", p, p0, p1) +} - function _tframex_p0(A, f, q, i, B, C) - { - _tframe_qparam = q - delete _TEND[++_TEND[_ARRLEN]] - if (match(f, /\~(.*)$/, B)) { - A["^~"] = A[".~"] = B[1] - f = substr(f, 1, RSTART - 1) - } - A["."] = A["^"] = f +#_______________________________________________ +function _tframe2_i1(A, p, p0, p1) +{ + if (_TEND[_ARRLEN] in _TEND) { return - q = split(f, B, /;/) - i = 0 - while (i < q) { - _tframex_p1(A, C[i]) - while (++i <= q) { - _tframex_p1(A, C[i], B[i]) - } - } } - - function _tframex_p1(A, v, i, r, B) - { - gsub(/[ \t]+/, "", v) - while (match(v, /^([^~]*)~\/(([^\/\\]*\\.)*[^\/\\]*)\//, B)) { - v = B[1] substr(v, RSTART + RLENGTH) - r = B[2] - } - if (i == "") { - if (v != "") { - A["."] = v - delete A["`"] - delete A["^"] - } - if (r != "") { - A[".~"] = A["`~"] = A["^~"] = r - } - } else { - if (match(v, /!/)) { - delete A[i] - } else { - A[i] = v - if (r != "") { - A[i "~"] = r - } - } - } + if (p in _tNEXT) { + return (_tframe2_i0(A, p, p0, p1) _tframe2_i1(A, _tNEXT[p], p0, p1)) } + return _tframe2_i0(A, p, p0, p1) +} - function _tgenuid(c) - { - for (_uidcntr in _UIDARR1) { - delete _UIDARR1[_uidcntr] - for (c in _UIDARR0) { - _UIDS[_uidcntr c] - } - delete _UIDS[_uidcntr c] - return (_uidcntr c) - } - return _fatal("_tUID: Out of UID range") +#_______________________________________________ +function _tframe2_i2(A, m, p, p0, p1) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tgenuid_init(a, b, A) - { - _ptrlength = 4 - a = "\222\223\224\225\226\227\230\231\232" "\240\241\242\243\244\245\246\247" "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" - split(a, A, "") - for (a in A) { - for (b in A) { - _UIDARR0[A[a] A[b]] _UIDARR1[A[a] A[b]] + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } } - _uidcntr = A[a] A[b] + m = A[m] + return @m(p, p0, p1) } +} - function _tgetitem(p, n, a, b) - { - if (p) { - if (isarray(_PTR[p]["ITEM"]) && n in _PTR[p]["ITEM"]) { - a = _PTR[p]["ITEM"][n] - } else { - a = _PTR[p]["ITEM"][n] = _N() - } - if (! (b = _rFCHLD(a))) { - b = _wLCHLD(a, _N()) - _PTR[b]["HOST"] = p - _[b]["ITEMNAME"] = n - } - return b +#_________________________________________________________________ +function _tframe3(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe3_i0(f, p, p0, p1, p2) } + _tframex_p0(A, f, 3) + return _th0(_tframe3_i0(A, p, p0, p1, p2), --_TEND[_ARRLEN]) } +} - function _tgetsp(p) - { - return _tSTACK[p][0] +#_______________________________________________ +function _tframe3_i0(A, p, p0, p1, p2) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _th0(p, p1, p2, p3) - { - return p - } - - function _th1(p0, p, p2, p3) - { - return p - } - - function _th10(p0, p1) - { - return (p1 p0) + if (p in _tFCHLD) { + return (_tframe3_i2(A, "^", p, p0, p1, p2) _tframe3_i1(A, _tFCHLD[p], p0, p1, p2)) } + return _tframe3_i2(A, ".", p, p0, p1, p2) +} - function _th2(p0, p1, r, p3) - { - return p +#_______________________________________________ +function _tframe3_i1(A, p, p0, p1, p2) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } - - function _th3(p0, p1, p2, r) - { - return p + if (p in _tNEXT) { + return (_tframe3_i0(A, p, p0, p1, p2) _tframe3_i1(A, _tNEXT[p], p0, p1, p2)) } + return _tframe3_i0(A, p, p0, p1, p2) +} - function _tifend(l) - { - return ((_t_ENDF[0] + l in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : "")) +#_______________________________________________ +function _tframe3_i2(A, m, p, p0, p1, p2) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tinit_i0(D, S, i) - { - for (i in S) { - if (isarray(S[i])) { - if (! isarray(D[i][""])) { - delete D[i] - D[i][""] - delete D[i][""] - } - _N_i0(D[i], S[i]) - } else { - if (isarray(D[i])) { - delete D[i] - } - D[i] = S[i] + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } } + m = A[m] + return @m(p, p0, p1, p2) } +} - function _tlist(L, p, f) - { - _tlisti1 = _tlisti0 = L[_ARRLEN] + 0 - if (f == 0 && f == "") { - _tlist_i0(L, p) - } else { - _tlistf0 = (f in _TAPI ? _TAPI[f] : f) - _tlist_i1(L, p) +#_________________________________________________________________ +function _tframe4(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe4_i0(f, p, p0, p1, p2, p3) } - return (_tlisti0 - _tlisti1) + _tframex_p0(A, f, 4) + return _th0(_tframe4_i0(A, p, p0, p1, p2, p3), --_TEND[_ARRLEN]) } +} - function _tlist_i0(L, p, q, i) - { - if (isarray(p)) { - q = p[_ARRLEN] - i = 0 - while (i++ < q) { - _tlist_i0(L, p[i]) - } - return - } - if (p in _) { - while (p in _tLINK) { - p = _tLINK[p] - } - L[++_tlisti0] = p - if (p in _tFCHLD) { - for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { - _tlist_i0(L, p) - } - } - } +#_______________________________________________ +function _tframe4_i0(A, p, p0, p1, p2, p3) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } + if (p in _tFCHLD) { + return (_tframe4_i2(A, "^", p, p0, p1, p2, p3) _tframe4_i1(A, _tFCHLD[p], p0, p1, p2, p3)) + } + return _tframe4_i2(A, ".", p, p0, p1, p2, p3) +} - function _tlist_i1(L, p) - { - if (isarray(p)) { - q = p[_ARRLEN] - i = 0 - while (i++ < q) { - _tlist_i1(L, p[i]) +#_______________________________________________ +function _tframe4_i1(A, p, p0, p1, p2, p3) +{ + if (_TEND[_ARRLEN] in _TEND) { + return + } + if (p in _tNEXT) { + return (_tframe4_i0(A, p, p0, p1, p2, p3) _tframe4_i1(A, _tNEXT[p], p0, p1, p2, p3)) + } + return _tframe4_i0(A, p, p0, p1, p2, p3) +} + +#_______________________________________________ +function _tframe4_i2(A, m, p, p0, p1, p2, p3) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] + } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - return } - if (p in _) { - while (p in _tLINK) { - p = _tLINK[p] - } - if (_tlistf0 in _[p]) { - L[++_tlisti0] = p + m = A[m] + return @m(p, p0, p1, p2, p3) + } +} + +#___________________________________________________________ +function _tframe_i0(f, p, p0, p1, p2, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmframe_i0(f, _tFCHLD[p], p0, p1, p2) : (p in _tDLINK ? @f(_tDLINK[p], p0, p1, p2) : @f(p, p0, p1, p2)))) +} + +#___________________________________________________________ +function _tframe_i1(F, p, p0, p1, p2, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? (("." in F ? _th1(a = F["."], @a(p, p0, p1, p2)) : "")) _tmframe_i1(F, _tFCHLD[p], p0, p1, p2) : (">" in F ? _th1(a = F[">"], (p in _tDLINK ? @a(_tDLINK[p], p0, p1, p2) : @a(p, p0, p1, p2))) : ""))) +} + +#_______________________________________________________________________ +function _tframex(f, p, p0, p1) +{ + ############################################ + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tframex_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tframex_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmframex(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________ +function _tframex_p0(A, f, q, i, B, C) +{ + _tframe_qparam = q + delete _TEND[++_TEND[_ARRLEN]] + if (match(f, /\~(.*)$/, B)) { + A["^~"] = A[".~"] = B[1] + f = substr(f, 1, RSTART - 1) + } + A["."] = A["^"] = f + return + q = split(f, B, /;/) + i = 0 + while (i < q) { + _tframex_p1(A, C[i]) + while (++i <= q) { + _tframex_p1(A, C[i], B[i]) + } + } +} + +#_______________________________________________ +function _tframex_p1(A, v, i, r, B) +{ + gsub(/[ \t]+/, "", v) + while (match(v, /^([^~]*)~\/(([^\/\\]*\\.)*[^\/\\]*)\//, B)) { + v = B[1] substr(v, RSTART + RLENGTH) + r = B[2] + } + if (i == "") { + if (v != "") { + A["."] = v + delete A["`"] + delete A["^"] + } + if (r != "") { + A[".~"] = A["`~"] = A["^~"] = r + } + } else { + if (match(v, /!/)) { + delete A[i] + } else { + A[i] = v + if (r != "") { + A[i "~"] = r + } + } + } +} + +#_____________________________________________________ +# F v action +#----------------------------------------------------- +# - * no additional action +# A B delete A[p] and define A[p] as array; copy array B to array A[p] +# A - delete A[p] +# A "*" delete A[p]; A[p]="*" +# "*" B define _[p]["*"] as array; copy array B to array _[p]["*"] +# "*" - run _mpu program "*" for `p +# "*0" "*1" _[p]["*0"]="*1" +#___________________________________________________________ +function _tgenuid(c) +{ + for (_uidcntr in _UIDARR1) { + delete _UIDARR1[_uidcntr] + for (c in _UIDARR0) { + _UIDS[_uidcntr c] + } + delete _UIDS[_uidcntr c] + return (_uidcntr c) + } + return _fatal("_tUID: Out of UID range") +} + +#_____________________________________________________ +function _tgenuid_init(a, b, A) +{ + _ptrlength = 4 + a = "\222\223\224\225\226\227\230\231\232" "\240\241\242\243\244\245\246\247" "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + split(a, A, "") + for (a in A) { + for (b in A) { + _UIDARR0[A[a] A[b]] _UIDARR1[A[a] A[b]] + } + } + _uidcntr = A[a] A[b] +} + +# if ( F in _TCLASS ) { _[p]["CLASS"]=_TCLASS[F]; _tapi(p); return p } +# # ??? _mpu(F,p) ??? +# return p } +# _[p][F]=v; return p } + +#_______________________________________________________________________ +function _tgetitem(p, n, a, b) +{ + ############################################ + if (p) { + if (isarray(_PTR[p]["ITEM"]) && n in _PTR[p]["ITEM"]) { + a = _PTR[p]["ITEM"][n] + } else { + a = _PTR[p]["ITEM"][n] = _N() + } + if (! (b = _rFCHLD(a))) { + b = _wLCHLD(a, _N()) + _PTR[b]["HOST"] = p + _[b]["ITEMNAME"] = n + } + return b + } +} + +#_________________________________________________________________ +function _tgetsp(p) +{ + ############################################### + return _tSTACK[p][0] +} + +#################################################################################### + +#_____________________________________________________________________________ +function _th0(p, p1, p2, p3) +{ + return p +} + +########################################## +#_________________________________________________________________ +function _th1(p0, p, p2, p3) +{ + return p +} + +############################## +#_________________________________________________________________ +function _th10(p0, p1) +{ + return (p1 p0) +} + +############################## +#_________________________________________________________________ +function _th2(p0, p1, r, p3) +{ + return p +} + +############################## +#_________________________________________________________________ +function _th3(p0, p1, p2, r) +{ + return p +} + +#_________________________________________________________________ +function _tifend(l) +{ + ############################################### + return ((_t_ENDF[0] + l in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : "")) +} + +# test _tbrochld fn; develope tOBJ r\w func specification for brochld func + +#_________________________________________________________________ +function _tinit_i0(D, S, i) +{ + for (i in S) { + if (isarray(S[i])) { + if (! isarray(D[i][""])) { + delete D[i] + D[i][""] + delete D[i][""] } - if (p in _tFCHLD) { - for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { - _tlist_i1(L, p) - } + _N_i0(D[i], S[i]) + } else { + if (isarray(D[i])) { + delete D[i] } + D[i] = S[i] } } +} - function _tmbframe(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - t = t _tbframe_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) - } - return t - } +#_______________________________________________________________________ +######################################################################## - function _tmbframex(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - t = t _tbframex_i0(f, p, p0, p1) - p = (p in _tPREV ? _tPREV[p] : "") - } - return t - } - function _tmbpass(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) - } - return p0 - } - function _tmbpassx(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - p0 = _tbpassx_i0(f, p, p0, p1) - p = (p in _tPREV ? _tPREV[p] : "") - } - return p0 - } - function _tmframe(f, p, p0, p1, p2) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tmframe_i0(f, p, p0, p1, p2) : "") - --_t_ENDF[0] - return f - } - function _tmframe_i0(f, p, p0, p1, p2, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - t = t _tframe_i0(f, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return t - } - function _tmframe_i1(F, p, p0, p1, p2, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - t = t _tframe_i1(F, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return t - } - function _tmframex(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - t = t _tframex_i0(f, p, p0, p1) - p = (p in _tNEXT ? _tNEXT[p] : "") - } - return t - } - function _tmpass(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return p0 - } - function _tmpassx(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - p0 = _tbpassx_i0(f, p, p0, p1) - p = (p in _tNEXT ? _tNEXT[p] : "") - } - return p0 - } - function _torexp(r) - { - return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN) - } - function _torexp_cmdstr(t) - { - return _strtorexp(gensub(/\^(.)/, "\\1", "G", t)) - } - function _torexp_fmask(t) - { - return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t))) - } - function _torexp_init() - { - _TOREXPFN[""] = "_strtorexp" - _TOREXPFN["~"] = "_torexp_rexp" - _TOREXPFN["="] = "_strtorexp" - _TOREXPFN[">"] = "_torexp_cmdstr" - _TOREXPFN["#"] = "_torexp_fmask" - _TOREXPFN["\""] = "_torexp_dqstr" - _TOREXPFN["'"] = "_torexp_sqstr" - } - function _torexp_rexp(t) - { - return t - } - function _tpass(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tpass_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tpass_i0(f, p, p0, p1, a) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tpassx(f, p, p0, p1) - { - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tpassx_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tpassx_i0(f, p, p0, p1) - { - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tpop(p, aA, a) - { - if ((a = _tSTACK[p][0]) > 0) { - _tSTACK[p][0]-- - if (isarray(_tSTACK[p][a])) { - delete aA - _movarr(aA, _tSTACK[p][a]) - return - } - return _tSTACK[p][a] - } - _fatal("^" p ": Out of tSTACK") - } - function _tpush(p, aA, a) - { - if (isarray(aA)) { - delete _tSTACK[p][a = ++_tSTACK[p][0]] - _tSTACK[p][a][""] - delete _tSTACK[p][a][""] - _movarr(_tSTACK[p][a], aA) - return - } - delete _tSTACK[p][a = ++_tSTACK[p][0]] - return (_tSTACK[p][a] = aA) - } - - function _tr(n, cs, H) - { - _rconline(n ": " cs) - _rconl() - if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) { - _rconl("delptr: " _une(H[2]) "'") - _rconl("pfxstr: " _une(H[5]) "'") - _rconl("hichr: " _une(H[7]) "'") - _rconl("lochr: " _une((H[10] ? H[7] "' and " H[11] "'" : H[11] "'"))) - _rconl("sfxstr: " _une(H[14]) "'") - } else { - _rconl("NOT MATCH!") - } - _rconl() - } - function _trace(t, d, A) - { - if (_ERRLOG_TF) { - A["TYPE"] = "TRACE" - A["TEXT"] = t - _log(A, d) - } - } - function _trunframe(f, p, p0, p1, p2) - { - return _tframe((f ? f : "_trunframe_i0"), p, p0, p1, p2) - } +#_______________________________________________________________________ +# _N(arr\str\mpuptr,val) \ _n(arr\str\mpuptr,val) +# This functions create new object and return ptr. +# _n() - creates object from list of deleted objects or if it's empty create new one, while _N() always create new one +# It is strongly recommended to use _N() for the objects that have some data outside of standart object arrays. Or - make routines +# that will clear outsided object data in case if object deleting. +# +# IN: arr\str\mpu,val - (both missed) just create obj and return ptr +# arr,val - create object and write arr[ptr]=val +# str,val - create object and write _[ptr][str]=val +# mpuptr - NOT ALLOWED (val missed) create object and run MPU-code specified by mpuptr with created object ptr as primary parameter +# MOD: - +# OUT: - +# RETURN: ptr - pointer to newly created object +#_________________________________________________________________ +# _tdel(ptr) +# This function exclude object from it's current structure and delete it. ptr can be later used by function: _n() for creating new object +# Also same story will occured with all chields and subchields of object specified by ptr. +# ??? What happened with linked py _ptr[ptr] objects ??? +# +# IN: ptr - pointer to object that will deleted +# MOD: - +# OUT: - +# RETURN: undefined +#_________________________________________________________________ +# _isptr(ptr) +# This function checks: is ptr is the object pointer that is currently exist? +# Unescaped remained data will be in data of src_dst_ptr. +# +# IN: ptr - string that will be tested +# MOD: - +# OUT: - +# RETURN: undefined - if ptr is not pointer to exist object +# ptr - if ptr is the pointer to exist object +#_________________________________________________________________ - function _trunframe_i0(p, p0, p1, p2, f) - { - if (p in _tFN) { - f = _tFN[p] - return @f(p, p0, p1, p2) - } - } - function _trunframex(f, p, p0, p1) - { - return _tframex((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _trunpass(f, p, p0, p1) - { - return _tpass((f ? f : "_trunframe_i0"), p, p0, p1) - } +#_________________________________________________________________ +# +# TO DESIGN: +# +# create basic objectapi interface support +# modify everywhere checking ptr not by `if ( ptr )...', but by `if ( ptr in _ )...' +# _TMP0, _TMP1 name change to something like _DATA name ??? +# think about redesigning routines for not depending if ptr is exist in tsysarrs: reason: performance\light code - function _trunpassx(f, p, p0, p1) - { - return _tpassx((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tsetsp(p, v) - { - return (_tSTACK[p][0] = v) - } - function _tstini() - { - _ini("uidel:pfx'hstr|lstr'sfx") - _ini("uidel:pfx'hstr|lstr'") - _ini("uidel:'hstr|lstr'sfx") - _ini("uidel:'hstr|lstr'") - _ini("uidel:pfx'hstr'sfx") - _ini("uidel:pfx'hstr'") - _ini("uidel:'hstr'sfx") - _ini("uidel:'hstr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'hstr|lstr'sfx") - _ini("pfx'hstr|lstr'") - _ini("'hstr|lstr'sfx") - _ini("'hstr|lstr'") - _ini("pfx'hstr'sfx") - _ini("pfx'hstr'") - _ini("'hstr'sfx") - _ini("'hstr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("uidel:pfx'`cntptr'sfx") - _ini("uidel:pfx'`cntptr'") - _ini("uidel:'`cntptr'sfx") - _ini("uidel:'`cntptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'`cntptr'sfx") - _ini("pfx'`cntptr'") - _ini("'`cntptr'sfx") - _ini("'`cntptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("uidel:pfx'^chrptr'sfx") - _ini("uidel:pfx'^chrptr'") - _ini("uidel:'^chrptr'sfx") - _ini("uidel:'^chrptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'^chrptr'sfx") - _ini("pfx'^chrptr'") - _ini("'^chrptr'sfx") - _ini("'^chrptr'") - _conl() - _conl("########################################################################################") - _conl() - } - function _tstv(p, A, r, f) - { - if (f == "") { - f = "tst_splitstr" - } - @f(_NOP, A, p) - @f(AA0, A, p) - @f(AB0, A, p) - @f(AC0, A, p) - @f("", A, p) - @f("a", A, p) - @f("\264a", A, p) - @f("\264", A, p) - @f("a\264\264\264,ba\264\264\264,", A, p) - @f("\264,", A, p) - @f(",", A, p) - @f("\264a,", A, p) - @f("ab,", A, p) - @f("ab,\264", A, p) - @f("\264a\264,,ba", A, p) - @f(",a,,b\264,c,,\264a,,\264,,,", A, p) - } - function _typ(p) - { - return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in _CLASSPTR ? "`" : (p ? 3 : 4))) : (p in _CLASSPTR ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) - } - function _typa(p, A) - { - return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in A ? "`" : (p ? 3 : 4))) : (p in A ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) - } - function _tzend(a, b) - { - if (b == 0 && b == "") { - return (_TEND[_TEND[_ARRLEN]] = a) - } else { - return (_TEND[_TEND[_ARRLEN] + a] = b) - } - } - function _uidcyc(p, i) - { - _dumpuidgen(p) - for (i = 1; i < 64 * 8 * 6 - 1; i++) { - _conl(i ":" _var(_getuid(p))) - } - _dumpuidgen(p) - } - function _une(t) - { - return gensub(/\xB4(.)/, "\\1", "G", t) - } - function _unformatrexp(t) - { - _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCREXP[_FORMATSTRB[t]] : _QESCREXP[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _unformatrexp_init(i, a) - { - _formatstrs0 = "\\^$.[]|()*+?{}-sSwW<>yB`'" - delete _FORMATSTRB - for (i = 0; i < 256; i++) { - _QESCREXP["\\" _CHR[i]] = (index(_formatstrs0, _CHR[i]) ? "\\" _CHR[i] : _CHR[i]) - } - for (i = 0; i < 256; i++) { - a = (index(_formatstrs0, _CHR[i]) ? "\\" : "") - _QESCREXP[sprintf("%.2X", i)] = a _CHR[i] - _QESCREXP["\\" sprintf("%.3o", i)] = a _CHR[i] - if (i < 8) { - _QESCREXP["\\" sprintf("%.1o", i)] = a _CHR[i] - } - if (i < 64) { - _QESCREXP["\\" sprintf("%.2o", i)] = a _CHR[i] - } - if (i < 16) { - _QESCREXP["\\x" sprintf("%.1X", i)] = _QESCREXP["\\x" sprintf("%.1x", i)] = a _CHR[i] - } - } - patsplit("a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) - for (i in _FORMATSTRA) { - _QESCREXP["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] - } +function _tlist(L, p, f) +{ + _tlisti1 = _tlisti0 = L[_ARRLEN] + 0 + if (f == 0 && f == "") { + _tlist_i0(L, p) + } else { + _tlistf0 = (f in _TAPI ? _TAPI[f] : f) + _tlist_i1(L, p) } + return (_tlisti0 - _tlisti1) +} - function _unformatstr(t) - { - _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) +function _tlist_i0(L, p, q, i) +{ + if (isarray(p)) { + q = p[_ARRLEN] + i = 0 + while (i++ < q) { + _tlist_i0(L, p[i]) } - return (_formatstrs0 _FORMATSTRA[t]) + return } - - function _unformatstr_init(i) - { - for (i = 0; i < 256; i++) { - _QESCHR["\\" _CHR[i]] = _CHR[i] - } - for (i = 0; i < 256; i++) { - _QESCHR[sprintf("%.2X", i)] = _CHR[i] - _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i] - if (i < 8) { - _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i] - } - if (i < 64) { - _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i] - } - if (i < 16) { - _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i] - } - } - i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11 - patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) - for (i in _FORMATSTRA) { - _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] + if (p in _) { + while (p in _tLINK) { + p = _tLINK[p] } - } - - function _uninit_del(A, i, p0) - { - _del(i) - } - - function _unstr(t) - { - return gensub(/\\(.)/, "\\1", "G", t) - } - - function _untmp(f, a) - { - if (f = filepath(f)) { - if (match(f, /\\$/)) { - _deletepfx(_FILEIO_RDTMP, a = toupper(f)) - _deletepfx(_FILEIO_RDNETMP, a) - } else { - delete _FILEIO_RDNETMP[toupper(f)] + L[++_tlisti0] = p + if (p in _tFCHLD) { + for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { + _tlist_i0(L, p) } - return f } - return "" } +} - function _val(v, t) - { - if (isarray(v)) { - return (_dumparr(v) _ln(t)) - } - if (v == 0 && v == "") { - return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) +function _tlist_i1(L, p) +{ + if (isarray(p)) { + q = p[_ARRLEN] + i = 0 + while (i++ < q) { + _tlist_i1(L, p[i]) } - return (_ln(v "'") _ln(t)) + return } - - function _val0(v) - { - if (isarray(v)) { - return _dumparr(v) - } - if (v == 0 && v == "") { - return "-" + if (p in _) { + while (p in _tLINK) { + p = _tLINK[p] } - return ("\"" v "\"") - } - - function _var(v, t) - { - if (isarray(v)) { - return (_dumparr(v) _ln(t)) + if (_tlistf0 in _[p]) { + L[++_tlisti0] = p } - if (v == 0 && v == "") { - return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + if (p in _tFCHLD) { + for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { + _tlist_i1(L, p) + } + } + } +} + +#_________________________________________________________________ +function _tmbframe(f, p, p0, p1, t) +{ + ################################## + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tbframe_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) + } + return t +} + +#_________________________________________________________________ +function _tmbframex(f, p, p0, p1, t) +{ + ################################# + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tbframex_i0(f, p, p0, p1) + p = (p in _tPREV ? _tPREV[p] : "") + } + return t +} + +#_________________________________________________________________ +function _tmbpass(f, p, p0, p1) +{ + ###################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) + } + return p0 +} + +#_________________________________________________________________ +function _tmbpassx(f, p, p0, p1) +{ + ##################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpassx_i0(f, p, p0, p1) + p = (p in _tPREV ? _tPREV[p] : "") + } + return p0 +} + +#_________________________________________________________________ +function _tmframe(f, p, p0, p1, p2) +{ + ################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tmframe_i0(f, p, p0, p1, p2) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tmframe_i0(f, p, p0, p1, p2, t) +{ + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframe_i0(f, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return t +} + +#___________________________________________________________ +function _tmframe_i1(F, p, p0, p1, p2, t) +{ + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframe_i1(F, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return t +} + +#_________________________________________________________________ +function _tmframex(f, p, p0, p1, t) +{ + ################################## + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframex_i0(f, p, p0, p1) + p = (p in _tNEXT ? _tNEXT[p] : "") + } + return t +} + +#_________________________________________________________________ +function _tmpass(f, p, p0, p1) +{ + ####################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return p0 +} + +#_________________________________________________________________ +function _tmpassx(f, p, p0, p1) +{ + ###################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpassx_i0(f, p, p0, p1) + p = (p in _tNEXT ? _tNEXT[p] : "") + } + return p0 +} + +function _torexp(r) +{ + return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN) +} + +function _torexp_cmdstr(t) +{ + return _strtorexp(gensub(/\^(.)/, "\\1", "G", t)) +} + +function _torexp_fmask(t) +{ + return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t))) +} + +#_______________________________________________ +function _torexp_init() +{ + _TOREXPFN[""] = "_strtorexp" + _TOREXPFN["~"] = "_torexp_rexp" + _TOREXPFN["="] = "_strtorexp" + _TOREXPFN[">"] = "_torexp_cmdstr" + _TOREXPFN["#"] = "_torexp_fmask" + _TOREXPFN["\""] = "_torexp_dqstr" + _TOREXPFN["'"] = "_torexp_sqstr" +} + +#_______________________________________________ +function _torexp_rexp(t) +{ + return t +} + +#_____________________________________________________________________________ +function _tpass(f, p, p0, p1) +{ + #################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tpass_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tpass_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tpassx(f, p, p0, p1) +{ + ################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tpassx_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tpassx_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_________________________________________________________________ +function _tpop(p, aA, a) +{ + ########################################### + if ((a = _tSTACK[p][0]) > 0) { + _tSTACK[p][0]-- + if (isarray(_tSTACK[p][a])) { + delete aA + _movarr(aA, _tSTACK[p][a]) + return } - return (_ln(v "'") _ln(t)) + return _tSTACK[p][a] } + _fatal("^" p ": Out of tSTACK") +} - function _verb(t, d, A) - { - if (_ERRLOG_VF) { - A["TYPE"] = "VERB" - A["TEXT"] = t - _log(A, d) - } +#_____________________________________________________________________________ +function _tpush(p, aA, a) +{ + ###################################################### + if (isarray(aA)) { + delete _tSTACK[p][a = ++_tSTACK[p][0]] + _tSTACK[p][a][""] + delete _tSTACK[p][a][""] + _movarr(_tSTACK[p][a], aA) + return } - - function _wFBRO(p, v, a) - { - if (p) { - if (v) { - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } - if (p in _tPARENT) { - p = _tPARENT[p] - if (v in _tNEXT) { - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - delete _tPREV[v] - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) - } - --_tQCHLD[a] - } - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tPREV[_tFCHLD[a] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] - } - } - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } else { - if (v in _tPREV) { - if (v in _tPARENT) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - if (p == a) { - delete _tPREV[v] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) - } - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - delete _tPREV[v] - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tFCHLD[a] - delete _tLCHLD[a] - delete _tQCHLD[a] - } - } - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } - } else { - while (p in _tPREV) { - p = _tPREV[p] - } - if (v in _tPREV) { - if (v in _tPARENT) { - --_tQCHLD[a = _tPARENT[v]] - delete _tPARENT[v] - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - } else { - delete _tNEXT[_tLCHLD[a] = _tPREV[v]] - } - } else { - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - } else { - delete _tNEXT[_tPREV[v]] - } - } - delete _tPREV[v] - } else { - if (p == v) { - return v - } - if (v in _tPARENT) { - if (v in _tNEXT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tLCHLD[a = _tPARENT[v]] - delete _tFCHLD[a] - delete _tQCHLD[a] - } - delete _tPARENT[v] - } else { - if (v in _tNEXT) { - delete _tPREV[_tNEXT[v]] - } - } - } - return (_tPREV[_tNEXT[v] = p] = v) - } - } else { - if (v == 0) { - return v - } - return v - } + delete _tSTACK[p][a = ++_tSTACK[p][0]] + return (_tSTACK[p][a] = aA) +} + +# prefix - +# prichr - aware character `{', `^',`]' +# sechr - aware character `.' as the first char of sechr, and character `}' +# suffix - aware character `]' +# cntptr - aware character `]' + +function _tr(n, cs, H) +{ + #_tuidinitcs[p]=cs + #2 uidel, 5 pfx, 7 hichr,11(10) lochr,14 suffix + _rconline(n ": " cs) + _rconl() + if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) { + _rconl("delptr: " _une(H[2]) "'") + _rconl("pfxstr: " _une(H[5]) "'") + _rconl("hichr: " _une(H[7]) "'") + _rconl("lochr: " _une((H[10] ? H[7] "' and " H[11] "'" : H[11] "'"))) + _rconl("sfxstr: " _une(H[14]) "'") + } else { + _rconl("NOT MATCH!") + } + _rconl() +} + +#_______________________________________________________________________ +function _trace(t, d, A) +{ + ################################################# + if (_ERRLOG_TF) { + A["TYPE"] = "TRACE" + A["TEXT"] = t + _log(A, d) + } +} + +#_________________________________________________________________ +function _trunframe(f, p, p0, p1, p2) +{ + ################################# + return _tframe((f ? f : "_trunframe_i0"), p, p0, p1, p2) +} + +#_________________________________________________________________ +function _trunframe_i0(p, p0, p1, p2, f) +{ + if (p in _tFN) { + f = _tFN[p] + return @f(p, p0, p1, p2) + } +} + +#_________________________________________________________________ +function _trunframex(f, p, p0, p1) +{ + ################################### + return _tframex((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _trunpass(f, p, p0, p1) +{ + ##################################### + return _tpass((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _trunpassx(f, p, p0, p1) +{ + #################################### + return _tpassx((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tsetsp(p, v) +{ + ############################################# + return (_tSTACK[p][0] = v) +} + +# dptr - morg ptr; in case if object deleted then _CLASSPTR[ptr] will be deleted(object is death), but +# _tUIDEL[_CLASSPTR[ptr]] will be created that object can be resurrected from morg +# dptr can be any string containing any characters except `:'. It's not verified +# pfx,sfx - uid prefix str, and uid suffix str; this strings specifies string that can be inserted before/after +# uid generated by uid generator: +# +# class uid: pfx uidgen sfx +# +# Both can be any string(including ""), and can contains any character with B4-escaping feature. +# Note: that this strings cannot contains "'" character: it's should be escaped by B4-escaper. +# hstr,lstr - this values configure uid-generator itself. ther is a 3 combinations regarding its: +# +# hstr lstr function +# +# `ptr * - specify pointer to external uid-generator +# All uids and chars will be generated by external uid-generator +# * ^ptr - class will have it's own uid generator using external character set +# str str - class will have it's own uid generator with it's own character set +# character set inmplemented in hstr(high-charset) and in lstr(low-charset) in 2 ways: +# 1) "AB" "AB01" - this mean that high-charset contain chars: `A' and `B' +# low-charset contains chars: `A', `B', `0', `1' +# +# 2) "Az,By" "Ax,Bw,0v,1u" - this mean that high-charset contain chars: `Az' and `By' +# low-charset contains chars: `Ax', `Bw', `0v', `1u' +# Note: both: hstr and lstr cannot contain char `,' directly, but it's can uses +# B4-escaper to escape any char including `,' + + + +# !!!! in case of using `,' in hstr/lstr - the escaped `,' will leads to interpretate hstr and lstr as divided by `,' +# if parameters error then i should be more specific about what error in parameters detected +# document _inituid(): parameters; document cs: uid initialization string format +# test with escape char +# adv hstr and lstr splitting? +# chk if hstr len==0 ? +# return _tclass & report error? +# _tapi thru function + +# additional syntax checking ??? +# implement syntax and uid srv in docs +# add _dumpuid() ???? +# make performance measurement +# protection against badchar list +# additional feature to specify _getuid() to not resurrect uid; and informative that uid was ressurected or not +# build _defclass fn + +# _tuidinitcs ???? +# _tuidchrh[p] +# _tuidchrl[p] +# _tuidchr[p] +# _tuidcnt[p] +# _tUIDPFX[p] +# _tUIDSFX[p] +# _tUIDEL +# _tUIDCNTH +# _tUIDCNTL +# _tUIDCHRL +# _tUIDCHRH + +# create default class basic `new' and `del' functions + + + +function _tstini() +{ + _ini("uidel:pfx'hstr|lstr'sfx") + _ini("uidel:pfx'hstr|lstr'") + _ini("uidel:'hstr|lstr'sfx") + _ini("uidel:'hstr|lstr'") + _ini("uidel:pfx'hstr'sfx") + _ini("uidel:pfx'hstr'") + _ini("uidel:'hstr'sfx") + _ini("uidel:'hstr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'hstr|lstr'sfx") + _ini("pfx'hstr|lstr'") + _ini("'hstr|lstr'sfx") + _ini("'hstr|lstr'") + _ini("pfx'hstr'sfx") + _ini("pfx'hstr'") + _ini("'hstr'sfx") + _ini("'hstr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("uidel:pfx'`cntptr'sfx") + _ini("uidel:pfx'`cntptr'") + _ini("uidel:'`cntptr'sfx") + _ini("uidel:'`cntptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'`cntptr'sfx") + _ini("pfx'`cntptr'") + _ini("'`cntptr'sfx") + _ini("'`cntptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("uidel:pfx'^chrptr'sfx") + _ini("uidel:pfx'^chrptr'") + _ini("uidel:'^chrptr'sfx") + _ini("uidel:'^chrptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'^chrptr'sfx") + _ini("pfx'^chrptr'") + _ini("'^chrptr'sfx") + _ini("'^chrptr'") + _conl() + _conl("########################################################################################") + _conl() +} + +function _tstv(p, A, r, f) +{ + if (f == "") { + f = "tst_splitstr" + } + @f(_NOP, A, p) + @f(AA0, A, p) + @f(AB0, A, p) + @f(AC0, A, p) + @f("", A, p) + @f("a", A, p) + @f("\264a", A, p) + @f("\264", A, p) + @f("a\264\264\264,ba\264\264\264,", A, p) + @f("\264,", A, p) + @f(",", A, p) + @f("\264a,", A, p) + @f("ab,", A, p) + @f("ab,\264", A, p) + @f("\264a\264,,ba", A, p) + @f(",a,,b\264,c,,\264a,,\264,,,", A, p) +} + +function _typ(p) +{ + return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in _CLASSPTR ? "`" : (p ? 3 : 4))) : (p in _CLASSPTR ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) +} + +function _typa(p, A) +{ + return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in A ? "`" : (p ? 3 : 4))) : (p in A ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) +} + +#_____________________________________________________ +# _tframe0(hndstr,ptr) +# +# +# IN: +# MOD: +# OUT: +# RETURN: +# +# handler string: +# Handler-string divides to words. Word splitter is char ";" +# +# Note that handler-string processed left to right. This mean that next word(more rightly) will overwrite fields implemented before(leftmost). +# Note that if word-string contains more than one rexp-field then only last rexp-field(most rightly) will be applied. +#_______________________________________________ +# TO DESIGN: +# +# 0-4: complete design of tlink handler call +# 1-4: add new tlink handler call +# 1-4: add new run fn (changed rexp to different for each type: see _tframe0) +# +# hndstr: +# may be add rexp for each type of handler and also total rexp for all ??? ADDED (test) +# may be add separator char ";" ??? ADDED (test) +#_______________________________________________________________________ +function _tzend(a, b) +{ + ##################################################### + if (b == 0 && b == "") { + return (_TEND[_TEND[_ARRLEN]] = a) + } else { + return (_TEND[_TEND[_ARRLEN] + a] = b) + } +} + +function _uidcyc(p, i) +{ + _dumpuidgen(p) + for (i = 1; i < 64 * 8 * 6 - 1; i++) { + _conl(i ":" _var(_getuid(p))) + } + _dumpuidgen(p) +} + +function _une(t) +{ + return gensub(/\xB4(.)/, "\\1", "G", t) +} + +#___________________________________________________________________________________ +function _unformatrexp(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCREXP[_FORMATSTRB[t]] : _QESCREXP[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) + } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _unformatrexp_init(i, a) +{ + _formatstrs0 = "\\^$.[]|()*+?{}-sSwW<>yB`'" + delete _FORMATSTRB + for (i = 0; i < 256; i++) { + _QESCREXP["\\" _CHR[i]] = (index(_formatstrs0, _CHR[i]) ? "\\" _CHR[i] : _CHR[i]) + } + for (i = 0; i < 256; i++) { + a = (index(_formatstrs0, _CHR[i]) ? "\\" : "") + _QESCREXP[sprintf("%.2X", i)] = a _CHR[i] + _QESCREXP["\\" sprintf("%.3o", i)] = a _CHR[i] + if (i < 8) { + _QESCREXP["\\" sprintf("%.1o", i)] = a _CHR[i] + } + if (i < 64) { + _QESCREXP["\\" sprintf("%.2o", i)] = a _CHR[i] + } + if (i < 16) { + _QESCREXP["\\x" sprintf("%.1X", i)] = _QESCREXP["\\x" sprintf("%.1x", i)] = a _CHR[i] + } + } + patsplit("a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) + for (i in _FORMATSTRA) { + _QESCREXP["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] + } +} + +#___________________________________________________________________________________ +function _unformatstr(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) + } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _unformatstr_init(i) +{ + for (i = 0; i < 256; i++) { + _QESCHR["\\" _CHR[i]] = _CHR[i] + } + for (i = 0; i < 256; i++) { + _QESCHR[sprintf("%.2X", i)] = _CHR[i] + _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i] + if (i < 8) { + _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i] + } + if (i < 64) { + _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i] + } + if (i < 16) { + _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i] + } + } + i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11 + patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) + for (i in _FORMATSTRA) { + _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] + } +} + +#_____________________________________________________________________________ +function _uninit_del(A, i, p0) +{ + _del(i) +} + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# var _SYS_STDOUT - (by default = "/dev/stdout") standart output pipe filename +# var _SYS_STDERR - (by default = "/dev/stderr") standart error output pipe filename +# var _SYS_STDCON - (by default = "CON") standart console output device +#_____________________________________________________________________________ +# var _CHR["CR"] - return cursor to the position 0 without newline(normally ="\x0D") +# var _CHR["EOL"] - return cursor to the position 0 & newline (MS:="\x0D\x0A" / UX:="\x0D") +# var _CON_WIDTH - console width(columns number) +#_____________________________________________________________________________ +# fn _cmd(c) - execute shell command c and return output +# fn _err - output string w\o any addition into _SYS_STDERR device +# fn _errnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDERR device +# fn _out - output string w\o any addition into _SYS_STDOUT device +# fn _outnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDOUT device +#_____________________________________________________________________________ +# fn _con(text[,tabspace]) +# fn _conl(text[,tabspace]) +# fn _conline(text[,tabspace]) +# fn _constat(status[,tabspace]) +# fn _constatpush([status[,tabspace]]) +# fn _constatpop() +#_______________________________________________________________________ +# var _constatstr +#################################################################################### + + +function _unstr(t) +{ + return gensub(/\\(.)/, "\\1", "G", t) +} + +#_________________________________________________________________ +function _untmp(f, a) +{ + ############################################# + if (f = filepath(f)) { + if (match(f, /\\$/)) { + _deletepfx(_FILEIO_RDTMP, a = toupper(f)) + _deletepfx(_FILEIO_RDNETMP, a) } else { - if (p == 0) { - return v - } - if (v) { - return _texclude(v) - } - return v + delete _FILEIO_RDNETMP[toupper(f)] } + return f } - - function _wFCHLD(p, v, a) - { - if (p) { - if (v) { - if (p == v) { + return "" +} + +#_____________________________________________________________________________ +function _val(v, t) +{ + if (isarray(v)) { + return (_dumparr(v) _ln(t)) + } + if (v == 0 && v == "") { + return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + } + return (_ln(v "'") _ln(t)) +} + +#_____________________________________________________________________________ +function _val0(v) +{ + if (isarray(v)) { + return _dumparr(v) + } + if (v == 0 && v == "") { + return "-" + } + return ("\"" v "\"") +} + +#_____________________________________________________________________________ +function _var(v, t) +{ + if (isarray(v)) { + return (_dumparr(v) _ln(t)) + } + if (v == 0 && v == "") { + return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + } + return (_ln(v "'") _ln(t)) +} + +#_______________________________________________________________________ +function _verb(t, d, A) +{ + ################################################## + if (_ERRLOG_VF) { + A["TYPE"] = "VERB" + A["TEXT"] = t + _log(A, d) + } +} + +#_________________________________________________________________ +function _wFBRO(p, v, a) +{ + ########################################### + if (p) { + if (v) { + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } + } + ######################## v is parentesis of p + if (p in _tPARENT) { + p = _tPARENT[p] if (v in _tNEXT) { if (v in _tPREV) { _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] @@ -5925,11 +7271,8 @@ delete _tPREV[_tNEXT[v]] } } - if (p in _tFCHLD) { - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } - delete _tNEXT[v] + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } else { if (v in _tPREV) { if (v in _tPARENT) { @@ -5953,167 +7296,184 @@ delete _tQCHLD[a] } } - if (p in _tFCHLD) { - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } - _tQCHLD[p] = 1 - return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v) } else { - if (v == 0) { - if (p in _tFCHLD) { - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + while (p in _tPREV) { + p = _tPREV[p] + } + if (v in _tPREV) { + if (v in _tPARENT) { + --_tQCHLD[a = _tPARENT[v]] + delete _tPARENT[v] + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + } else { + delete _tNEXT[_tLCHLD[a] = _tPREV[v]] + } + } else { + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + } else { + delete _tNEXT[_tPREV[v]] + } + } + delete _tPREV[v] + } else { + if (p == v) { + return v + } + if (v in _tPARENT) { + if (v in _tNEXT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + --_tQCHLD[a] + } else { + delete _tLCHLD[a = _tPARENT[v]] + delete _tFCHLD[a] + delete _tQCHLD[a] + } + delete _tPARENT[v] + } else { + if (v in _tNEXT) { + delete _tPREV[_tNEXT[v]] + } } } - return v + return (_tPREV[_tNEXT[v] = p] = v) } } else { - if (p == 0) { + if (v == 0) { return v } + ######################## p=ptr, v=0 + return v + } + } else { + ######################## p=ptr, v="" + if (p == 0) { return v } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v + return v } +} - function _wLBRO(p, v, a) - { - if (p) { - if (v) { - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } +#_________________________________________________________________ +function _wFCHLD(p, v, a) +{ + ########################################## + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { + return v } - if (p in _tPARENT) { - p = _tPARENT[p] - if (v in _tPREV) { - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - delete _tNEXT[v] - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) - } - --_tQCHLD[a] - } - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tNEXT[_tLCHLD[a] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - } - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } else { - if (v in _tNEXT) { - if (v in _tPARENT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - if (p == a) { - delete _tNEXT[v] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) - } - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] - } - delete _tNEXT[v] - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tLCHLD[a] - delete _tFCHLD[a] - delete _tQCHLD[a] - } + } + ######################## v is parentesis of p + if (v in _tNEXT) { + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + delete _tPREV[v] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) } - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) + --_tQCHLD[a] } } else { - while (p in _tNEXT) { - p = _tNEXT[p] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v + } + delete _tPREV[_tFCHLD[a] = _tNEXT[v]] + --_tQCHLD[a] + } else { + delete _tPREV[_tNEXT[v]] } - if (v in _tNEXT) { - if (v in _tPARENT) { - --_tQCHLD[a = _tPARENT[v]] - delete _tPARENT[v] - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - } else { - delete _tPREV[_tFCHLD[a] = _tNEXT[v]] - } - } else { - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - } else { - delete _tPREV[_tNEXT[v]] - } + } + if (p in _tFCHLD) { + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) + } + delete _tNEXT[v] + } else { + if (v in _tPREV) { + if (v in _tPARENT) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + if (p == a) { + delete _tPREV[v] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) } - delete _tNEXT[v] + --_tQCHLD[a] } else { - if (p == v) { + delete _tNEXT[_tPREV[v]] + } + delete _tPREV[v] + } else { + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { return v } - if (v in _tPARENT) { - if (v in _tPREV) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tFCHLD[a = _tPARENT[v]] - delete _tLCHLD[a] - delete _tQCHLD[a] - } - delete _tPARENT[v] - } else { - if (v in _tPREV) { - delete _tNEXT[_tPREV[v]] - } - } + delete _tFCHLD[a] + delete _tLCHLD[a] + delete _tQCHLD[a] } - return (_tNEXT[_tPREV[v] = p] = v) } - } else { - if (v == 0) { - return v + if (p in _tFCHLD) { + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } - return v } + _tQCHLD[p] = 1 + return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v) } else { - if (p == 0) { - return v - } - if (v) { - return _texclude(v) + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } } return v } + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v + } + ######################## p=0 + return v } +} - function _wLCHLD(p, v, a) - { - if (p) { - if (v) { - if (p == v) { +#_________________________________________________________________ +function _wLBRO(p, v, a) +{ + ########################################### + if (p) { + if (v) { + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } + } + ######################## v is parentesis of p + if (p in _tPARENT) { + p = _tPARENT[p] if (v in _tPREV) { if (v in _tNEXT) { _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] @@ -6135,11 +7495,8 @@ delete _tNEXT[_tPREV[v]] } } - if (p in _tLCHLD) { - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } - delete _tPREV[v] + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } else { if (v in _tNEXT) { if (v in _tPARENT) { @@ -6163,596 +7520,802 @@ delete _tQCHLD[a] } } - if (p in _tLCHLD) { - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } - _tQCHLD[p] = 1 - return (_tLCHLD[_tPARENT[v] = p] = _tFCHLD[p] = v) } else { - if (v == 0) { - if (p in _tFCHLD) { - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + while (p in _tNEXT) { + p = _tNEXT[p] + } + if (v in _tNEXT) { + if (v in _tPARENT) { + --_tQCHLD[a = _tPARENT[v]] + delete _tPARENT[v] + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + } else { + delete _tPREV[_tFCHLD[a] = _tNEXT[v]] + } + } else { + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + } else { + delete _tPREV[_tNEXT[v]] + } + } + delete _tNEXT[v] + } else { + if (p == v) { + return v + } + if (v in _tPARENT) { + if (v in _tPREV) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + --_tQCHLD[a] + } else { + delete _tFCHLD[a = _tPARENT[v]] + delete _tLCHLD[a] + delete _tQCHLD[a] + } + delete _tPARENT[v] + } else { + if (v in _tPREV) { + delete _tNEXT[_tPREV[v]] + } } } - return v + return (_tNEXT[_tPREV[v] = p] = v) } } else { - if (p == 0) { + if (v == 0) { return v } + ######################## p=ptr, v=0 return v } + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v + } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v + return v } +} - function _wLINK(p, v) - { - return (_tLINK[p] = v) - } - - function _wNEXT(p, v, a, b) - { - if (p) { - if (v) { - if (p == v) { +#_________________________________________________________________ +function _wLCHLD(p, v, a) +{ + ########################################## + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } - if (v in _tPREV) { - if (p == (a = _tPREV[v])) { - return v - } - if (v in _tNEXT) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a - if (v in _tPARENT) { - --_tQCHLD[_tPARENT[v]] - } - } else { - delete _tNEXT[a] - if (v in _tPARENT) { - _tLCHLD[b = _tPARENT[v]] = a - --_tQCHLD[b] + } + ######################## v is parentesis of p + if (v in _tPREV) { + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + delete _tNEXT[v] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) } + --_tQCHLD[a] } } else { - if (v in _tNEXT) { - if (v in _tPARENT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v } + delete _tNEXT[_tLCHLD[a] = _tPREV[v]] + --_tQCHLD[a] } else { - if (v in _tPARENT) { - delete _tFCHLD[a = _tPARENT[v]] - delete _tLCHLD[a] - delete _tQCHLD[a] - } + delete _tNEXT[_tPREV[v]] } } - if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + if (p in _tLCHLD) { + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) + } + delete _tPREV[v] + } else { + if (v in _tNEXT) { + if (v in _tPARENT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + if (p == a) { + delete _tNEXT[v] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) + } + --_tQCHLD[a] } else { - delete _tPARENT[v] + delete _tPREV[_tNEXT[v]] } - } else { delete _tNEXT[v] - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]] - } else { - delete _tPARENT[v] + } else { + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v + } + delete _tLCHLD[a] + delete _tFCHLD[a] + delete _tQCHLD[a] } } - return (_tNEXT[_tPREV[v] = p] = v) - } else { - if (v == 0) { - return v + if (p in _tLCHLD) { + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } - return v } + _tQCHLD[p] = 1 + return (_tLCHLD[_tPARENT[v] = p] = _tFCHLD[p] = v) } else { - if (p == 0) { - return v - } - if (v) { - return _texclude(v) + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } } return v } - } - - function _wPARENT(p, v) - { + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v + } + ######################## p=0 return v } - - function _wPREV(p, v, a, b) - { - if (p) { - if (v) { - if (p == v) { +} + +#_________________________________________________________________ +function _wLINK(p, v) +{ + ############################################## + return (_tLINK[p] = v) +} + +#_________________________________________________________________ +function _wNEXT(p, v, a, b) +{ + ######################################### + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } + } + ######################## v is parentesis of p + if (v in _tPREV) { + if (p == (a = _tPREV[v])) { + return v } if (v in _tNEXT) { - if (p == (a = _tNEXT[v])) { - return v - } - if (v in _tPREV) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a - if (v in _tPARENT) { - --_tQCHLD[_tPARENT[v]] - } - } else { - delete _tPREV[a] - if (v in _tPARENT) { - _tFCHLD[b = _tPARENT[v]] = a - --_tQCHLD[b] - } + _tPREV[_tNEXT[a] = _tNEXT[v]] = a + if (v in _tPARENT) { + --_tQCHLD[_tPARENT[v]] } } else { - if (v in _tPREV) { - if (v in _tPARENT) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - } else { - if (v in _tPARENT) { - delete _tLCHLD[a = _tPARENT[v]] - delete _tFCHLD[a] - delete _tQCHLD[a] - } + delete _tNEXT[a] + if (v in _tPARENT) { + _tLCHLD[b = _tPARENT[v]] = a + --_tQCHLD[b] } } - if (p in _tPREV) { - _tNEXT[_tPREV[v] = _tPREV[p]] = v - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + if (v in _tNEXT) { + if (v in _tPARENT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + --_tQCHLD[a] } else { - delete _tPARENT[v] + delete _tPREV[_tNEXT[v]] } } else { - delete _tPREV[v] - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]] - } else { - delete _tPARENT[v] + if (v in _tPARENT) { + delete _tFCHLD[a = _tPARENT[v]] + delete _tLCHLD[a] + delete _tQCHLD[a] } } - return (_tPREV[_tNEXT[v] = p] = v) + } + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + delete _tPARENT[v] + } } else { - if (v == 0) { - return v + delete _tNEXT[v] + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]] + } else { + delete _tPARENT[v] } - return v } + return (_tNEXT[_tPREV[v] = p] = v) } else { - if (p == 0) { + if (v == 0) { return v } - if (v) { - return _texclude(v) - } + ######################## p=ptr, v=0 return v } - } - - function _wQBRO(p, v) - { + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v + } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v return v } - - function _wQCHLD(p, v) - { - if (p) { - if (v) { +} + +#_________________________________________________________________ +function _wPARENT(p, v) +{ + ############################################ + return v +} + +#_________________________________________________________________ +function _wPREV(p, v, a, b) +{ + ######################################### + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { + return v + } + } + ######################## v is parentesis of p + if (v in _tNEXT) { + if (p == (a = _tNEXT[v])) { + return v + } + if (v in _tPREV) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a + if (v in _tPARENT) { + --_tQCHLD[_tPARENT[v]] + } + } else { + delete _tPREV[a] + if (v in _tPARENT) { + _tFCHLD[b = _tPARENT[v]] = a + --_tQCHLD[b] + } + } } else { - if (v == 0) { - if (p in _tFCHLD) { - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + if (v in _tPREV) { + if (v in _tPARENT) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + --_tQCHLD[a] + } else { + delete _tNEXT[_tPREV[v]] + } + } else { + if (v in _tPARENT) { + delete _tLCHLD[a = _tPARENT[v]] + delete _tFCHLD[a] + delete _tQCHLD[a] } } - return v } + if (p in _tPREV) { + _tNEXT[_tPREV[v] = _tPREV[p]] = v + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + delete _tPARENT[v] + } + } else { + delete _tPREV[v] + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]] + } else { + delete _tPARENT[v] + } + } + return (_tPREV[_tNEXT[v] = p] = v) } else { - if (p == 0) { + if (v == 0) { return v } + ######################## p=ptr, v=0 return v } - } - - function _warning(t, d, A) - { - if (_ERRLOG_WF) { - A["TYPE"] = "WARNING" - A["TEXT"] = t - _log(A, d) + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v + return v } - - function _wfilerdnehnd(f, t) - { - if ((f = _filerdne(f)) == "") { - return "" +} + +#_________________________________________________________________ +function _wQBRO(p, v) +{ + ############################################## + return v +} + +#_________________________________________________________________ +function _wQCHLD(p, v) +{ + ############################################# + if (p) { + if (v) { + } else { + ######################## p=ptr, v=ptr + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } + } + return v } - if (! ((t = _filerd(f)) in _WFILEROOTDIR)) { - _cmd("md \"" t "\" 2>NUL") - _WFILEROOTDIR[t] + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v } - return f + ######################## p=0 + return v } +} - function _wonl(t) - { - wonl = wonl _ln(t) +#_______________________________________________________________________ +function _warning(t, d, A) +{ + ############################################### + if (_ERRLOG_WF) { + A["TYPE"] = "WARNING" + A["TEXT"] = t + _log(A, d) } +} - function _wonline(t) - { - wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126)) +#___________________________________________________________ +function _wfilerdnehnd(f, t) +{ + if ((f = _filerdne(f)) == "") { + return "" } - - function _wr_shortcut(f, S) - { - if (_shrtcutf0 = _filepath(f)) { - ERRNO = "" - _shrtcuta0 = _shortcut_fpath " /A:C /F:\"" _shrtcutf0 "\" 2>&1" - for (f in _SHORTCUTWSTRUC) { - if (f in S) { - _shrtcuta0 = _shrtcuta0 " " _SHORTCUTWSTRUC[f] "\"" (gensub(/(\\?)$/, "\\1\\1", 1, S[f])) "\"" - } - } - if (_shortcut_nerr(_cmd(_shrtcuta0), _shrtcutf0)) { - return - } - } - return ((ERRNO ? ERRNO = "write shortcut: " ERRNO : _NOP)) + if (! ((t = _filerd(f)) in _WFILEROOTDIR)) { + _cmd("md \"" t "\" 2>NUL") + _WFILEROOTDIR[t] } + return f +} - function _wrfile(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" - ERRNO = "" - print(d) > f - if (ERRNO) { - return "" - } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" - } - return f - } +function _wonl(t) +{ + wonl = wonl _ln(t) +} - function _wrfile1(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" +function _wonline(t) +{ + wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126)) +} + +#___________________________________________________________ +function _wr_shortcut(f, S) +{ + if (_shrtcutf0 = _filepath(f)) { ERRNO = "" - print(d) > f - if (ERRNO) { - return "" + _shrtcuta0 = _shortcut_fpath " /A:C /F:\"" _shrtcutf0 "\" 2>&1" + for (f in _SHORTCUTWSTRUC) { + if (f in S) { + _shrtcuta0 = _shrtcuta0 " " _SHORTCUTWSTRUC[f] "\"" (gensub(/(\\?)$/, "\\1\\1", 1, S[f])) "\"" + } } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" + if (_shortcut_nerr(_cmd(_shrtcuta0), _shrtcutf0)) { + return } - return d } + return ((ERRNO ? ERRNO = "write shortcut: " ERRNO : _NOP)) +} - function _yexport(p) - { - return _tframe("_yexport_i0", p) +#_________________________________________________________________ +function _wrfile(f, d, a, b) +{ + ######################################### + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function _yexport_i0(p, p0, p1, p2) - { - if (p in _tLOG) { - return ("_ERRLOG: " _Zexparr(_tLOG[p]) "\n") - } - if (p in _tSTR) { - p = _tSTR[p] - gsub(/\x1B/, "\033;", p) - gsub(/\x0A/, "\033:", p) - return (p "\n") - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) > f + if (ERRNO) { + return "" } - - function cmp_str_idx(i1, v1, i2, v2) - { - return ((i1 < i2 ? -1 : 1)) + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" } + return f +} - function filedi(f, d) - { - if ((f = filerdnehndi(f)) == "") { - return _FILEIO_D - } - if (f in _FILEDIRFL) { - return _FILEDIR[f] - } - if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] - } - return (_FILEDIR[f] = d _FILEDIR[f]) - } - if ((_FILEIO_RD, f) in _FILEDIR) { - return _FILEDIR[_FILEIO_RD, f] - } - return (_FILEDIR[_FILEIO_RD, f] = _FILEIO_D _FILEDIR[f]) +#___________________________________________________________ +function _wrfile1(f, d, a, b) +{ + ################################## + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function filegetdrvdir(t, r) - { - if (t in _FILEDRV) { - return _FILEDRV[t] - } - if (match(r = _cmd("cd " t " 2>NUL"), /[^\x00-\x1F]+/)) { - r = gensub(/[ \t]*([\\\$\:])[ \t]*/, "\\1", "G", substr(r, RSTART, RLENGTH)) - gsub(/(^[ \t]*)|([ \t]*$)/, "", r) - if (match(r, /\:(.*)/)) { - return (_FILEDRV[tolower(t)] = _FILEDRV[toupper(t)] = substr(r, RSTART + 1) ((r ~ /\\$/ ? "" : "\\"))) - } - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) > f + if (ERRNO) { return "" } - - function filegetrootdir(f, dd, d) - { - if (f in _FILEDIRFL) { - if (f in _FILEROOT) { - return (_FILEROOT[f] _FILEDIR[f]) - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - return (_FILEROOT[dd, f] _FILEDIR[f]) - } - return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[f]) - } + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" + } + return d +} + +#_______________________________________________________________________ +function _yexport(p) +{ + ##################################################### + return _tframe("_yexport_i0", p) +} + +#_______________________________________________________________________ +function _yexport_i0(p, p0, p1, p2) +{ + if (p in _tLOG) { + return ("_ERRLOG: " _Zexparr(_tLOG[p]) "\n") + } + if (p in _tSTR) { + p = _tSTR[p] + gsub(/\x1B/, "\033;", p) + gsub(/\x0A/, "\033:", p) + return (p "\n") + } +} + +#_________________________________________________________________ +function cmp_str_idx(i1, v1, i2, v2) +{ + ############################## + return ((i1 < i2 ? -1 : 1)) +} + +#___________________________________________________________ +function filedi(f, d) +{ + if ((f = filerdnehndi(f)) == "") { + return _FILEIO_D + } + if (f in _FILEDIRFL) { + return _FILEDIR[f] + } + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] + } + return (_FILEDIR[f] = d _FILEDIR[f]) + } + if ((_FILEIO_RD, f) in _FILEDIR) { + return _FILEDIR[_FILEIO_RD, f] + } + return (_FILEDIR[_FILEIO_RD, f] = _FILEIO_D _FILEDIR[f]) +} + +#___________________________________________________________ +function filegetdrvdir(t, r) +{ + if (t in _FILEDRV) { + return _FILEDRV[t] + } + if (match(r = _cmd("cd " t " 2>NUL"), /[^\x00-\x1F]+/)) { + r = gensub(/[ \t]*([\\\$\:])[ \t]*/, "\\1", "G", substr(r, RSTART, RLENGTH)) + gsub(/(^[ \t]*)|([ \t]*$)/, "", r) + if (match(r, /\:(.*)/)) { + return (_FILEDRV[tolower(t)] = _FILEDRV[toupper(t)] = substr(r, RSTART + 1) ((r ~ /\\$/ ? "" : "\\"))) + } + } + return "" +} + +#___________________________________________________________ +function filegetrootdir(f, dd, d) +{ + if (f in _FILEDIRFL) { if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] - return (_FILEROOT[f] (_FILEDIR[f] = d _FILEDIR[f])) - } else { - return (_FILEROOT[f] _FILEDIR[f]) - } + return (_FILEROOT[f] _FILEDIR[f]) } if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - if ((dd, f) in _FILEDIR) { - return (_FILEROOT[dd, f] _FILEDIR[dd, f]) - } - if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return (_FILEROOT[dd, f] (_FILEDIR[dd, f] = d)) - } - return (_FILEROOT[dd, f] d) + return (_FILEROOT[dd, f] _FILEDIR[f]) } + return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[f]) + } + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] + return (_FILEROOT[f] (_FILEDIR[f] = d _FILEDIR[f])) + } else { + return (_FILEROOT[f] _FILEDIR[f]) + } + } + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { if ((dd, f) in _FILEDIR) { - return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f]) + return (_FILEROOT[dd, f] _FILEDIR[dd, f]) } if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return ((_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d)) + return (_FILEROOT[dd, f] (_FILEDIR[dd, f] = d)) } - return ((_FILEROOT[dd, f] = fileri(dd)) d) + return (_FILEROOT[dd, f] d) + } + if ((dd, f) in _FILEDIR) { + return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f]) } + if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { + return ((_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d)) + } + return ((_FILEROOT[dd, f] = fileri(dd)) d) +} - function filerdnehndi(st, a, c, r, d, n, A) - { - if (st) { - if ((c = toupper(st)) in _FILECACHE) { - return _FILECACHE[c] - } - if (match(st, /^[ \t]*\\[ \t]*\\/)) { - if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { - a = a + RLENGTH - d = ((A[3] ? "\\" A[3] "$" : "")) "\\" A[5] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d - _FILEDIRFL[c] - _FILEROOT[c] = r - } else { - _filepath_err = "UNC" - return "" - } - } else { - match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) - if (! RLENGTH) { - return "" - } - d = A[8] A[10] +#___________________________________________________________ +function filerdnehndi(st, a, c, r, d, n, A) +{ + if (st) { + if ((c = toupper(st)) in _FILECACHE) { + return _FILECACHE[c] + } + if (match(st, /^[ \t]*\\[ \t]*\\/)) { + if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { + a = a + RLENGTH + d = ((A[3] ? "\\" A[3] "$" : "")) "\\" A[5] gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - if (A[8]) { - _FILEDIRFL[c] - } - if (r) { - _FILEROOT[c] = r + if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st]) } + _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d + _FILEDIRFL[c] + _FILEROOT[c] = r + } else { + _filepath_err = "UNC" + return "" } - if (n) { - if (match(n, /\.[^\.]*$/)) { - _FILEXT[c] = substr(n, RSTART) - _FILENAM[c] = substr(n, 1, RSTART - 1) - } else { - _FILENAM[c] = n - } + } else { + match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) + if (! RLENGTH) { + return "" + } + d = A[8] A[10] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st]) + } + _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + if (A[8]) { + _FILEDIRFL[c] + } + if (r) { + _FILEROOT[c] = r } - return c - } - return "" - } - - function fileri(f) - { - if ((f = filerdnehndi(f)) == "") { - return _FILEIO_R - } - if (f in _FILEROOT) { - return _FILEROOT[f] - } - if ((_FILEIO_RD, f) in _FILEROOT) { - return _FILEROOT[_FILEIO_RD, f] } - return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R) - } - - function hujf(a, b, c) - { - _conl("hujf(" a "," b "," c ")") - } - - function ncmp_str_idx(i1, v1, i2, v2) - { - return ((i1 < i2 ? 1 : -1)) - } - - function test_cfg(p, z, AA0, a) - { - AA0[1] - _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys) - _conl() - _conline() - _conl() - _drawuid(p) - _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys) - _conl() - _conline() - _conl() - _drawuid(p) - a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd")) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z)) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys)) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd") - _conl() - _conline() - _conl() - _drawuid(p) - _conl("```````````````````" z "'''''''''" ((_isptr(z) ? " ptr" : " not ptr"))) - _drawuid(z) - } - - function test_splitstr(A) - { - AA0[-1] = "huj" - AA0["A"] = "pizda" - AA0[1] = "zhopa" - delete AB0[AB0[""] = ""] - AC0[-1] = "HUJ" - AC0["A"] = "PIZDA" - AC0[1] = "ZHOPA" - _SPLITSTRB0["1"] - wonl = "" - _tstv(0, A, 0, "_tstv") - _conl(wonl) - _wrfile("wonl.out", wonl) - } - - function test_uid(p, i) - { - _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc") - _conl("_fclass uid: " _getuid(_fclass)) - _drawuid(_fclass) - _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys) - for (i = 1; i < 81; i++) { - _conl(i ": " _getuid(_fclass)) - } - _drawuid(_fclass) - } - - function tst_splitstr(t, A, R, r) - { - delete A - A["not cleared"] - _wonl() - _wonline("_splitstr(" ((isarray(t) ? "ARR" ((length(t) > 0 ? "#" ((t[1] != "zhopa" ? "U" : "l")) : "")) : _val0(t))) ",A" ((isarray(R) ? ", ARR" ((length(R) > 0 ? "#" ((R[1] != "zhopa" ? "U" : "l")) : "")) : ", " _val0(R))) "):") - _wonl(_val0(r = _splitstr(t, A, R))) - _wonl("arrary A:") - _wonl(_dumparr(A)) - return r - } - - function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im) - { - im = " " - im = ".. .." - _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'") - _conl("mask: `" _qparamask "'") - } - - function zorr(A, i, r) - { - if (i in A) { - _conl("`" i "' in A") - } else { - _conl("`" i "' not in A") + if (n) { + if (match(n, /\.[^\.]*$/)) { + _FILEXT[c] = substr(n, RSTART) + _FILENAM[c] = substr(n, 1, RSTART - 1) + } else { + _FILENAM[c] = n + } } - r = A[i] == "" && A[i] == 0 - _conl("A[" i "] status is " r) - return - a = a + -a - _conl("``````````````" a "''''''''''''''''") - } - - function zzer() - { + return c } + return "" +} + +#_____________________________________________________ +function fileri(f) +{ + if ((f = filerdnehndi(f)) == "") { + return _FILEIO_R + } + if (f in _FILEROOT) { + return _FILEROOT[f] + } + if ((_FILEIO_RD, f) in _FILEROOT) { + return _FILEROOT[_FILEIO_RD, f] + } + return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R) +} + +function hujf(a, b, c) +{ + _conl("hujf(" a "," b "," c ")") +} + +#___________________________________________________________ +function ncmp_str_idx(i1, v1, i2, v2) +{ + ####################### + return ((i1 < i2 ? 1 : -1)) +} + +function test_cfg(p, z, AA0, a) +{ + AA0[1] + _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys) + _conl() + _conline() + _conl() + _drawuid(p) + _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys) + _conl() + _conline() + _conl() + _drawuid(p) + a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd")) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z)) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys)) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd") + _conl() + _conline() + _conl() + _drawuid(p) + _conl("```````````````````" z "'''''''''" ((_isptr(z) ? " ptr" : " not ptr"))) + _drawuid(z) +} + +function test_splitstr(A) +{ + AA0[-1] = "huj" + AA0["A"] = "pizda" + AA0[1] = "zhopa" + delete AB0[AB0[""] = ""] + AC0[-1] = "HUJ" + AC0["A"] = "PIZDA" + AC0[1] = "ZHOPA" + _SPLITSTRB0["1"] + wonl = "" + _tstv(0, A, 0, "_tstv") + _conl(wonl) + _wrfile("wonl.out", wonl) +} + +function test_uid(p, i) +{ + #test_cfg() + #return + + _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc") + #_fclass=_cfguid(p=_getuid(_classys),_NOP,_NOP,_NOP,"",_classys) + _conl("_fclass uid: " _getuid(_fclass)) + _drawuid(_fclass) + _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys) + for (i = 1; i < 81; i++) { + _conl(i ": " _getuid(_fclass)) + } + _drawuid(_fclass) +} + +function tst_splitstr(t, A, R, r) +{ + delete A + A["not cleared"] + _wonl() + _wonline("_splitstr(" ((isarray(t) ? "ARR" ((length(t) > 0 ? "#" ((t[1] != "zhopa" ? "U" : "l")) : "")) : _val0(t))) ",A" ((isarray(R) ? ", ARR" ((length(R) > 0 ? "#" ((R[1] != "zhopa" ? "U" : "l")) : "")) : ", " _val0(R))) "):") + _wonl(_val0(r = _splitstr(t, A, R))) + _wonl("arrary A:") + _wonl(_dumparr(A)) + return r +} + +function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im) +{ + im = " " + im = ".. .." + _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'") + _conl("mask: `" _qparamask "'") +} + +# # - p is array +# ` - p is ptr detected in array _CLASSPTR(for _typ); or p is ptr detected in array A(for _typa) +# 0 - p is undefined + +# 2 - p is string=="" +# 3 - p is string!="" +# 4 - p is number 0 +# 5 - p is any number except 0(positive and negative) + +# str: _typ(p)+0 !_typ(p)+0 +# str/ptr _typ(p)>0 _typ(p)<1 +# str/arr "`">_typ(p0) && _t0 +# str/ptr/arr _typ(p) !_typ(p) +# ptr _typ(p)=="`" _typ(p)<"`" ? +# ptr/arr _typ(p)+0!=_t0 +# arr _typ(p)=="#" _typ(p)>"#" ? + +function zorr(A, i, r) +{ + if (i in A) { + _conl("`" i "' in A") + } else { + _conl("`" i "' not in A") + } + r = A[i] == "" && A[i] == 0 + _conl("A[" i "] status is " r) + return + a = a + -a + _conl("``````````````" a "''''''''''''''''") +} + +#_____________________________________________________________________________ +function zzer() +{ + ################################################################ +} diff --git a/test/profile6.awk b/test/profile6.awk new file mode 100644 index 00000000..754f8ae6 --- /dev/null +++ b/test/profile6.awk @@ -0,0 +1,7 @@ +BEGIN { + x = 3 + print -(-x) + Q = "|" + print -3 Q (-4) + print -3 Q (-4) (-5) +} diff --git a/test/profile6.ok b/test/profile6.ok new file mode 100644 index 00000000..0c9486c7 --- /dev/null +++ b/test/profile6.ok @@ -0,0 +1,10 @@ + # BEGIN rule(s) + + BEGIN { + 1 x = 3 + 1 print -(-x) + 1 Q = "|" + 1 print -3 Q (-4) + 1 print -3 Q (-4) (-5) + } + diff --git a/test/profile7.awk b/test/profile7.awk new file mode 100644 index 00000000..454694f9 --- /dev/null +++ b/test/profile7.awk @@ -0,0 +1,12 @@ +BEGIN { + print 1 / 10 * 10 + print 1 / (10 * 10) + print 1 % 10 * 10 + print 1 % (10 * 10) + print (10 * 5) / 2 + print 10 * (5 / 2) + a = 5 + b = 3 + print a - 1 - b + print a + 1 - b +} diff --git a/test/profile7.ok b/test/profile7.ok new file mode 100644 index 00000000..d65afa86 --- /dev/null +++ b/test/profile7.ok @@ -0,0 +1,15 @@ + # BEGIN rule(s) + + BEGIN { + 1 print 1 / 10 * 10 + 1 print 1 / (10 * 10) + 1 print 1 % 10 * 10 + 1 print 1 % (10 * 10) + 1 print 10 * 5 / 2 + 1 print 10 * 5 / 2 + 1 a = 5 + 1 b = 3 + 1 print a - 1 - b + 1 print a + 1 - b + } + diff --git a/test/testext.ok b/test/testext.ok index 5612e92c..9b36bf72 100644 --- a/test/testext.ok +++ b/test/testext.ok @@ -15,6 +15,7 @@ try_modify_environ: set_array_element of ENVIRON failed try_modify_environ: marking element "testext" for deletion try_del_environ() could not delete element - pass try_del_environ() could not add an element - pass +var_test: sym_lookup of PROCINFO passed - did not get a value var_test: sym_lookup of ARGC passed - got a value! var_test: sym_update of ARGC failed - correctly var_test: sym_update("testvar") succeeded diff --git a/vms/ChangeLog b/vms/ChangeLog index 9e055cf4..c7dd4233 100644 --- a/vms/ChangeLog +++ b/vms/ChangeLog @@ -1,3 +1,14 @@ +2014-10-17 John E. Malmberg <wb8tyw@qsl.net> + + * config_h.com: Use sys$disk: instead of prj_root: for + copying the configure file. + * gawk_alias_setup.com: Fix removal of out of date aliases. + * vmsbuild.com: Fix a typo for symbol CNAME and a case sensitive + test for "VAX" .eq. "vax" that failed. Also disable verify + while looking up the actual version. + * vmstest.com: Make sure that the test directory exists when + using a search list. + 2014-04-18 John E. Malmberg <wb8tyw@qsl.net> * gawk_alias_setup.com: Fix problem with file links on Vax/VMS. diff --git a/vms/config_h.com b/vms/config_h.com index c1d3becf..0074a65a 100644 --- a/vms/config_h.com +++ b/vms/config_h.com @@ -104,7 +104,7 @@ $! On some platforms, DCL search has problems with searching a file $! on a NFS mounted volume. So copy it to sys$scratch: $! $if f$search(configure_script) .nes. "" then delete 'configure_script';* -$copy PRJ_ROOT:configure 'configure_script' +$copy sys$disk:configure 'configure_script' $! $! $! Write out the header diff --git a/vms/vmsbuild.com b/vms/vmsbuild.com index c13e4b57..a46cc2ca 100644 --- a/vms/vmsbuild.com +++ b/vms/vmsbuild.com @@ -48,7 +48,7 @@ $ CFLAGS = "/Incl=[]/Obj=[]/Opt=noInline/Def=(''CDEFS')''CCFLAGS'" $ LIBS = "sys$share:vaxcrtl.exe/Shareable" $ else !!VAXC $! neither GNUC nor VAXC, assume DECC (same for either VAX or Alpha) -$ if arch_name .eqs. "vax" +$ if arch_name .eqs. "VAX" $ then $ CFLOAT = "" $ else @@ -58,7 +58,7 @@ $ CC = "cc/DECC/Prefix=All" $ CNAME = "/NAME=(AS_IS,SHORT) $ CINC = "/NESTED_INCLUDE=NONE" $ CFLAGS = "/Incl=([],[.vms])/Obj=[]/Def=(''CDEFS')''CINC'''CCFLAGS'" -$ CFLAGS = CNAMES + CFLOAT + CFLAGS +$ CFLAGS = CNAME + CFLOAT + CFLAGS $ LIBS = "" ! DECC$SHR instead of VAXCRTL, no special link option needed $ endif !VAXC $ endif !GNUC @@ -147,8 +147,8 @@ psect_attr=environ,noshr !extern [noshare] char ** stack=48 !preallocate more pages (default is 20) iosegment=128 !ditto (default is 32) $! -$ v1 = f$verify(1) $ @[.vms]gawk_ident.com +$ v1 = f$verify(1) $ open/append Fopt gawk.opt $ write Fopt libs $ close Fopt diff --git a/vms/vmstest.com b/vms/vmstest.com index 30bdbf22..a2ab9bff 100644 --- a/vms/vmstest.com +++ b/vms/vmstest.com @@ -27,6 +27,9 @@ $ gawk = "$sys$disk:[-]gawk" $ AWKPATH_srcdir = "define/User AWKPATH sys$disk:[]" $ AWKLIBPATH_dir = "define/User AWKLIBPATH sys$disk:[-]" $ +$! Make sure that the default directory exists on a search list. +$ def_dir = f$environment("default") +$ create/dir 'def_dir' $ listdepth = 0 $ pipeok = 0 $ floatmode = -1 ! 0: D_float, 1: G_float, 2: IEEE T_float |