diff options
84 files changed, 12081 insertions, 5429 deletions
@@ -1,9 +1,21 @@ +2019-01-14 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * builtin.c (do_typeof): Fix memory leak when populating the + optional array, and make sure to call the astore method. + 2019-01-14 Arnold D. Robbins <arnold@skeeve.com> * builtin.c (do_intdiv): Add unref of subscripts. * mpfr.c (do_mpfr_intdiv): Ditto. Thanks to Andy Schorr for noticing. +2019-01-09 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awkgram.y (tokentab): Indicate that typeof may take 2 arguments. + (snode): Add support for typeof's optional 2nd array argument. + * builtin.c (do_typeof): Add support for optional 2nd array arg, + returning flag info for scalars and backend array type for arrays. + 2019-01-09 John E. Malmberg <wb8tyw@qsl.net> * awk.h: For non GCC, have __attribute__ definition match @@ -15,6 +27,90 @@ the gettext return value if it's different from the original. Otherwise, use the original. +2019-01-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Use a struct instead of an array to contain the array methods + for improved code clarity and flexibility. + + * awk.h (array_funcs_t): Define new struct to contain the array + methods. + (NODE): Change type of array_funcs (sub.nodep.l.lp) from `afunc_t *' + to `const array_funcs_t *' (from a pointer to an array of function + methods to a pointer to a struct containing the methods). + (a*_ind): Remove obsolete method array index defines. + (a*): Redefine array methods to use struct members instead of + array elements. + (str_array_func, cint_array_func, int_array_func): Change type + from array of afunc_t to 'const array_funcs_t'. + (register_array_func): Remove global declaration, since this function + is called only inside array.c. + * array.c (null_array_func): Change from array of methods to a struct. + (array_types): Now an array of pointers to array_funcs_t. + (AFUNC): Remove obsolete macro. + (register_array_func): Change scope to static, and change argument + to a pointer to array_funcs_t instead of a pointer to an array of + methods. + (array_init): Modify calls to register_array_func to pass the address + of the new array method structs. + (make_array): Set array_funcs to & null_array_func. + (null_lookup): Modify to use new array method structs. + (assoc_list): Update cint check to use & cint_array_func. + * str_array.c (str_array_func, env_array_func): Change from array of + methods to an array_funcs_t struct. + (env_clear, init_env_array): Set array_funcs to & env_array_func. + * int_array.c (int_array_func): Change from array of methods to an + array_funcs_t struct. + * cint_array.c (cint_array_func): Ditto. + (cint_lookup): When setting xn->array_funcs, must now use &. + (cint_dump): Compare xn->array_funcs to & int_array_func. + +2019-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * array.c (do_delete): If the array is now empty, reset it to the + null implementation to avoid being locked into the backend + optimization previously selected. + +2019-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Remove pointless alength macro/method that uses a needless + function call indirection to access the table_size value. + + * awk.h (alength, alength_ind): Remove these defines, and also renumber + the array_funcs items after that, and use the <blah>_ind define to + define <blah> instead of repeating the hardcoded numeric value. + (NUM_AFUNCS): Remove unused define. + (assoc_length): Redefine to access table_size directly. + (null_length): Remove prototype. + * array.c (null_array_func): Remove null_length entry. + (null_length): Remove obsolete function. + * cint_array.c (cint_array_func): Remove null_length entry. + * int_array.c (int_array_func): Remove null_length entry. + * str_array.c (str_array_func, env_array_func): Remove null_length + entry. + * gawkapi.c (api_flatten_array_typed): Use the assoc_empty macro to + check for an empty array instead of comparing table_size to 0. + * symbol.c (lookup, check_param_names): Ditto. + +2018-12-31 Arnold D. Robbins <arnold@skeeve.com> + + Clean up namespace handling for the profiler. + + * awkgram.y (make_pp_namespace): Remove function, not needed. + (set_namespace): Use estrdup to save the current namespace. + * main.c (main): Before dumping the program, set current_namespace + to awk_namespace. + * profile.c (pprint): Use "awk" for comparison, not "awk::". + (pp_namespace): Just print the name in the @namespace line. + (adjust_namespace): Adjust for the fact that namespaces no longer + have the trailing "::". + +2018-12-30 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (check_qualified_name): Remove declaration. + * awkgram.y (check_qualified_special): Renamed from + check_qualified_name and made static. + * profile.c (pprint): Improve comment on namespace list. + 2018-12-21 Arnold D. Robbins <arnold@skeeve.com> * configure.ac: Remove -O only if .developing has 'debug' in it. @@ -27,6 +123,10 @@ * config.guess: Updated from GNULIB. +2018-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * TODO: Updated. + 2018-12-12 Andrew J. Schorr <aschorr@telemetry-investments.com> * configure.ac (AC_CHECK_FUNCS): Check for timegm. @@ -35,18 +135,93 @@ * protos.h (timegm): Add timegm proto on systems lacking it. * replace.c (timegm): Include missing_d/timegm.c if needed. +2018-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * NEWS: Updated some. + +2018-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h: Add new Op_K_namespace opcode for pretty printing. + * awkgram.y (namespace_chain): New variable, list of successive + @namespace directives seen, for the pretty printer. + (namespace_comment): Removed. + (set_namespace): Takes comment as second argument, builds the chain. + (mk_function, append_rule): Adjust to store the chain. + * debug.c (print_ns_list): New function. + (print_instruction): Adjust Op_rule and Op_func to use print_ns_list. + Add case for Op_K_namespace. + * eval.c (optable): Add entry for Op_K_namespace. + (opcode2str, op2str): Edit / add leading comments, respectively. + * profile.c (pp_namespace_list): New function. + (pprint): Adjust code to call pp_namespace_list. + 2018-12-06 Arnold D. Robbins <arnold@skeeve.com> * configure.ac: Add -ggdb3 to CFLAGS if developing and remove -O2 from Makefile, extension/Makefile, and support/Makefile. * config.guess, config.sub: Updated from GNULIB. +2018-12-06 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (namespace_comment): New variable. + (Grammar): Handle comments after @namespace statements. + (mk_function): Add any comment onto the saved namespace. + (append_rule): Ditto. + * profile.c (pp_namespace): Add second argument for a comment. + Adjust all calls. + +2018-12-02 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (mk_program): Add in leading and trailing comments + when program block is empty. + +2018-11-29 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (first_rule, func_first): Remove unused variables. + (Grammar): Simplify rule for range pattern. + +2018-11-28 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (debug_print_comment): New macro and function. + (load_library): Rework to not try to open the file if pretty printing. + (append_rule): Adjust handling of interblock_comment. + +2018-11-27 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (Grammar): In rule for function, set interblock_comment. + (mk_function): Hook interblock_comment onto fi->comment, merge it + with the existing one first, if any. Append trailing_comment. + +2018-11-26 Arnold D. Robbins <arnold@skeeve.com> + + * main.c (platform_name): Add os390. Treat Cygwin and Mac OS X + as POSIX, per discussion with the dev team. + + Unrelated: + + * profile.c (print_comment): Indent for chained comment. + * awkgram.y (load_library): Return early if just pretty printing. + (yylex): Fix handling of ?: and allow_newline etc. + +2018-11-25 Arnold D. Robbins <arnold@skeeve.com> + + * main.c (platform_name): New function returning platform name. + (load_procinfo): Use `platform_name()' to add "platform" element. + Thanks to Eli Zaretskii for the suggestion. + * NEWS: Updated with info about PROCINFO["platform"]. + 2018-11-25 Arnold D. Robbins <arnold@skeeve.com> * config.sub: Updated from GNULIB. 2018-11-24 Arnold D. Robbins <arnold@skeeve.com> + * awkgram.y (interblock_comment, pending_comment): New variables. + (Grammar, mk_program, add_rule): Adjust to use them. Changes + handle comments at the outermost level, between blocks and functions. + +2018-11-24 Arnold D. Robbins <arnold@skeeve.com> + * main.c (arg_assign): Allow assigning strongly typed regexp constants to variables on the command line and with -v. Thanks to Peng Yu <pengyu.ut@gmail.com> for the report. @@ -65,6 +240,47 @@ 2018-11-11 Arnold D. Robbins <arnold@skeeve.com> * main.c (usage): Improve output for -Z in the help. +2018-11-11 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (outer_comment): New variable. + (Grammar): More changes. We now get the simple case of leading + and trailing comments, but not all the cases. + +2018-11-11 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (trailing_comment): New variable. + (Grammar): For `action', append both trailing comments. This may + change. For `statements', append the value of `trailing_comment' + if set. At `statement := l_brace statements rbrace' save + trailing_comment from r_brace. + (make_braced_statements): Don't append the comment from r_brace + to the statement list. + +2018-10-30 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (NODE): New field: sub.nodep.x.cmnt, holds comment for + expressions being pretty-printed. + * awkgram.y (Grammar): For expression lists, save any comment + that came after a comma in the list. + * profile.c (pp_push): Accept a fourth argument which is any + comment associated with the expression. Either it's there or + it's NULL. Save it in the pp_comment field of the node being pushed. + (tabs, tabs_len, check_indent_level): Made into static globals. + (pprint): Adjust all calls to pp_push(). Fix parenthesization + for casts in string lengthes when indenting. + (pp_list): If a popped item has a comment, include it and the + following indentation in the formatted result. + +2018-10-28 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (include_source): Add second parameter to return + SRCFILE pointer. + (Grammar): For @include, save the comment for later dumping + along with the list of include files. + (make_include_comment): Removed. No longer used. + * profile.c: Update copyright year. + (print_include_list): New function. + (dump_prog): Call it. 2018-10-24 Arnold D. Robbins <arnold@skeeve.com> @@ -74,11 +290,121 @@ * config.sub: Updated from GNULIB. +2018-10-20 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (SRCFILE): Add comment field for comments on @load statements. + * awkgram.y (include_source): Type change to boolean. + (load_library): Type change to boolean, additiona parameter to + bring the SRCFILE struct up to where we can add the comment into it. + (make_include_comment): New function. Not used yet. + (Grammar): Add comment for @load statements. Start on preserving + @include statements and their comments for eventual inclusion + into the pretty-printed code. + * profile.c (print_lib_list): Made a little smarter about printing + the header and indentation. Print the comment if there is one. + +2018-10-17 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (commenttype): Add FOR_COMMENT. + * awkgram.y (Grammar): Handle all the opt_nls cases in + regular for statements. + * debug.c (print_instruction): Print the comments in Op_K_for. + * profile.c (pprint): Handle printing comments. + +2018-10-17 Arnold D. Robbins <arnold@skeeve.com> + + * NEWS: Updated. + * awkgram.y (Grammar): Distinguish `print' and `print $0' in + what gets profiled / pretty-printed. + * profile.c (pprint): For case and default, add final newline + if there is no comment to print. + +2018-10-16 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (Grammar): Improve comment handling for many plain + statements. Improve handling for case and default. + Handle comments in `for (iggy in foo)' loops. + (yylex): After a colon, only allow newline if was part of ?:. + (merge_comments): Improve coding so we don't get two newlines + at the end of a merged comment. + * debug.c (print_instruction): Handle comments for case and default. + Simplify printing of comments. + * profile.c (pprint): Handle comments for case and default. + Remove compiler warning in Op_and/Op_or handling. + +2018-10-14 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (Grammar): Add comment handling for do...while. + Regularize comments about `else ...'. + * debug.c (print_instruction): Improve handling of comments for + do-while and switch, and in general. + * profile.c (pprint): Revise for do...while. + +2018-10-10 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (make_braced_statements): New function. + (Grammar): Use it in the right places instead of inline code. + * debug.c (print_instruction): For Op_comment, fix type string. + * profile.c (pprint): Move tabs and tabs_len to top of function. + For Op_and and Op_or, handle comments. Use new check_indent_level + for Op_and, Op_or and Op_cond_exp. + 2018-10-10 Arnold D. Robbins <arnold@skeeve.com> * debug.c (print_instruction): For Op_comment, use print_func instead of fprintf to print the comment type. +2018-10-10 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (Grammar): For statement -> { statements }, fix comment + handling. For `if' statement add comment support. + * profile.c (pp_print): Print comments associated with `if' and `else'. + +2018-10-09 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (Grammar): Fix handling of empty statement (just a semi- + colon). + (merge_comments): If no chained comment and no second comment, + just return early. + +2018-10-09 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (enum commenttype): New enum. + (NODE): Add it to sub.val. + (EOL_COMMENT, FULL_COMMENT): Replaced with above enum values. + * awkgram.y (Grammar): Finish up handling comments in function headers + and bodies. Get trailing comments at end of program + (get_comment): When doing comments, if we got EOF, push it back so that + multiple comments get merged together. + (merge_comments): Allow second parameter to be NULL. + * profile.c (pp_print): Change to use above enum everywhere. For + Op_K_print_rec produce plain `print' instead of `print $0'. Handle + comments in ?:. Handle printing function comments. + (print_comment): Simplify `after_newline' assignment. Add assertion + that chaining is only two deep. + +2018-10-06 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (action): Improve handling of comments attached + to braces. Helps with function bodies. + +2018-10-04 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (merge_comments): Change return type to void. Adjust calls. + (Grammar): For action, pull comments out of braces and stick + into the list. For function_prologue, get comments from parameters + and ending newline, merge, and save. Wherever nls and opt_nls + are used, be sure to pass their values up via $$. For various + cases that can be empty, explicitly set $$ = NULL. + * profile.c (pprint): Get switch working. Get ?: working. + (print_comment): Print any chained comment. + (pp_func): Start revising. + +2018-10-03 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y: Range expressions, enable comment stuff. + Switch statement: start on comment handling. + 2018-10-01 Nelson H.F. Beebe <beebe@math.utah.edu> * custom.h (__builtin_expect): Define for non-GNU compilers. @@ -108,6 +434,23 @@ 2018-09-21 Arnold D. Robbins <arnold@skeeve.com> + * awk.h (INSTRUCTION): Add comment field to carry + comment around during parsing. + * awkgram.y (merge_comments): New function. + (split_comment, check_comment, comment, prior_comment, + comment_to_save, program_comment, function_comment, + block_comment): Removed. + (grammar): Remove old code and start passing the comment + up via yylval and the newlines in the grammar. + +2018-09-21 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y: Undo change of 2016-11-28 to make switch + head a separate production, in preparation for revamping + comment handling. + +2018-09-21 Arnold D. Robbins <arnold@skeeve.com> + * re.c (make_regexp): Handle backslash at end of input string. Thanks to Anatoly Trosinenko <anatoly.trosinenko@gmail.com> for the report. @@ -623,6 +966,25 @@ * field.c (do_split): Simplify the lint warnings. Based on suggested code by Eric Pruitt <eric.pruitt@gmail.com>. + Unrelated: + + * awkgram.y (check_funcs): Remove the REALLYMEAN ifdef and + simplify the lint checking code for function defined but not + called or called but not defined. + +2017-10-13 Arnold D. Robbins <arnold@skeeve.com> + + Assume a more C99 environment: + + * awk.h: Assume we have limits.h, stdarg.h and stdbool.h. + * configure.ac: Remove checks for limits.h and stdarg.h. + +2017-10-10 Arnold D. Robbins <arnold@skeeve.com> + + * configure.ac: Remove --with-whiny-user-strftime option. + * NEWS: Updated. + * ChangeLog.0: Fix a typo. :-) + 2017-10-08 Arnold D. Robbins <arnold@skeeve.com> * command.y: Fix the FSF's address. @@ -642,6 +1004,14 @@ 2017-10-02 Arnold D. Robbins <arnold@skeeve.com> + Undo change of 2014-09-07: + + * configure.ac: Remove the undocumented option to enable locale + letters in identifiers. + * awkgram.y (is_alpha): Remove related code. + +2017-10-02 Arnold D. Robbins <arnold@skeeve.com> + * config.guess, config.sub: Updated. 2017-09-28 Arnold D. Robbins <arnold@skeeve.com> @@ -782,6 +1152,69 @@ * awk.h: Add DJGPP in #if for include of nonposix.h * nonposix.h (btowc, putwc): Add declarations for DJGPP. +2017-07-26 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (validate_qualified_name): Return type back to bool. + * awkgram.y (validate_qualified_name): Return type back to bool. + (lookup_builtin): Make allowances for `awk::' prefix on name. + * interpret.h (r_interpret): For indirect call, always pass true + for do_qualify argument of lookup. + * main.c (main): Make note of errors in -v values, use this + to exit failure if any happen. Only change current_namespace + to 'awk::' if doing pretty printing. + (arg_assign): If validate_qualified name returns false, error out. + +2017-07-26 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (set_namespace): Change return type void, adjust + all return statements. + [@namespace]: Don't YYABORT on bad namespace so that we can check + the rest of the program. + (validate_qualified_name): Check traditional / posix first. Return + after printing an error message; we don't want to print multiple + messages for the same identifer. + * interpret.h (r_interpret): For indirect call, set do_qualify + parameter of lookup based on presence of a colon. + +2017-07-20 Arnold D. Robbins <arnold@skeeve.com> + + Make qualified names work with -v and command-line assignments. + + * awk.h (validate_qualified_name, check_qualified_name): Declare. + * awkgram.y (validate_qualified_name): No longer static. + (check_qualified_name): Ditto. + * main.c (arg_assign): Allow colons in identifiers. If not a + bad identifier, call validate_qualified_name and instead of + check_special use check_qualified_name. + +2017-07-17 Arnold D. Robbins <arnold@skeeve.com> + + Allow identifiers that are gawk extensions to be used as plain + identifiers outside the "awk" namespace. Make the real + builtins available via awk::builtin_name(). Standard awk reserved + words and builtin functions remain reserved. + + * awk.h (getfname): Add boolean parameter to prepend namespace + or not. + * awkgram.y (check_qualified_name): New function. Enforces that + standard awk reserved words and functions aren't allowed, and + allows awk::gawk_extension from non-"awk" namespace. + [direct_func_call]: Always convert name to fully qualified. + (getfname): Add boolean parameter to prepend namespace + or not. Adjust code. + (yylex): Separate out validation code from code building the + NAME token. Use check_qualified_name to decide if token is + special instead of check_special. + (validate_qualified_name): Just checks the form of the fully + qualified name. + * debug.c (print_instruction): Update call to getfname. + * profile.c (pprint): Update call to getfname. + +2017-07-17 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y [direct_func_call]: Save full variable name for + indirect calls too. + 2017-07-17 Arnold D. Robbins <arnold@skeeve.com> * awkgram.y [non_post_simp_exp]: Merge LEX_BUILTIN and @@ -802,6 +1235,42 @@ * re.c (research): Don't use dfa if need_start is true. +2017-07-13 Arnold D. Robbins <arnold@skeeve.com> + + More rationalization of the namespace code. + + * awk.h (is_valid_identifier): Declare. + * awkgram.y (grammar: direct_func_call): Store the fully qualified + name in the op code. + (yylex): Disallow reserved words and functions as namespace name. + (check_params): Small code edit + (validate_qualified_name): Use is_lsetter. + (set_namespace): Check for NULL pointer first! Use is_valid_identifier + instead of inline code. Disallow using reserved words as namespace + names. + * ext.c (is_valid_identifier): No longer static. + (make_builtin): Check name and namespace against reserved words and + fatal error if found. + * gawkapi.c (ns_lookup): New function to look for variables + in namespaces. + (api_sym_lookup): Check namespace for validity and use ns_lookup. + (api_sym_update): Ditto. + * profile.c (pp_print): Correctly print full function name + in a function call. + +2017-07-11 Arnold D. Robbins <arnold@skeeve.com> + + Continue adding namespace support to the extension API. + + * awk.h (make_builtin): Add leading name_space parameter. + * ext.c (make_builtin): Add leading name_space parameter. + Do the appropriate checking and building of a name before + installing in the symbol table. + * gawkapi.c (add_ext_func): Use name_space, not namespace. + Check that the parameter isn't NULL. + (api_sym_lookup, api_sym_update): Use name_space, not namespace. + * gawkapi.h: Use name_space, not namespace, everywhere. + 2017-07-11 Arnold D. Robbins <arnold@skeeve.com> * awk.h (is_letter): Add declaration. @@ -828,6 +1297,17 @@ 2017-07-07 Arnold D. Robbins <arnold@skeeve.com> + * awkgram.y (yyerror): Produce better diagnostics for source + files that are not whole syntactic units. + + * gawkapi.c (api_sym_lookup, api_sym_update): Add namespace parameter. + Currently unused. + * gawkapi.h (api_sym_lookup, api_sym_update): Add namespace parameter. + (api_sym_lookup_ns, api_sym_update_ns): New macros. + (api_sym_lookup, api_sym_update): Adjust macro bodies. + +2017-07-07 Arnold D. Robbins <arnold@skeeve.com> + * gawapi.h: Bring descriptive comments up to date, minor edits. * io.c: Add some initial comments to functions where they were missing. @@ -835,6 +1315,57 @@ * gawkapi.h, gawkapi.c: Typo fixes in comments. +2017-07-01 Arnold D. Robbins <arnold@skeeve.com> + + * symbol.c (install): Don't call fix_up_namespace if + installing parameters. + * profile.c (remove_namespace): Renamed to + (adjust_namespace): Make smarter and add boolean parameter for + if return was mallc'ed. Adjust calls. + +2017-06-30 Arnold D. Robbins <arnold@skeeve.com> + + Add namespace info into Op_Rule and Op_Func. + Fix memory management problem. + The changes temporarily break the test suite. + + * awk.h (MAX_INSTRUCTION_ALLOC): Increase to 4. + (Op_K_namespace): Remove, not needed. + * eval.c (optypetab): Remove Op_K_namespace. + * awkgram.y (make_pp_namespace): New function. + (yylex): For BEGIN etc, allocate 4 in the instruction. + (install_func): Save namespace name for Op_rule. + (append_rule): Save namespace name for Op_rule. + * debug.c (print_instruction): Print namespace for Op_rule, Op_func. + Remove Op_K_namespace. + * profile.c (pp_namespace, remove_namespace): New functions. + (pprint): Call `pp_namespace'. Use `remove_namespace' on variable + names. + (pp_func): Ditto on both. + * symbol.c (lookup): Initialize `malloced' to false. + (install): Ditto. + + Unbreak the test suite: + + * awk.h (namespace_changed): Declare new boolean variable. + * awkgram.y (namespace_changed): Define new boolean variable. + (set_namespace): Set it to true when the namespace is changed. + * main.c (main): Set current_namespace to "awk::" for the pretty + printer. + * profile.c (pp_namespace): If namespace_changed is false, return. + +2017-06-28 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h [ns_name]: Add macro in preparation for use. + * debug.c (print_instruction): Add case for Op_K_namespace. + Not really used yet. + * symbol.c (fix_up_namespace): Bug fix to always allocate + memory for a full name. Add boolean parameter to indicate + if memory was malloc'ed or not. + (lookup): Adjust call to fix_up_namespace and use make_str_node + if the string was malloced. + (install): Ditto. + 2017-06-26 Arnold D. Robbins <arnold@skeeve.com> * configure.ac: Turn a tab into a space in AC_DEFINE(SUPPLY_INTDIV). @@ -894,6 +1425,62 @@ * config.guess, config.sub: Update to latest from GNULIB. * gettext.h: Pull in a few nice changes from GNULIB version. +2017-06-16 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (lookup): Add second parameter. + * array.c (assoc_list): Adjust call to lookup. + * awkgram.y (grammar, parms_shadow, install_function, variable): + Ditto. + * command.y [Grammar]: Ditto. + * debug.c (find_symbol): Ditto. + * ext.c (make_builtin): Ditto. + * gawkapi.c (api_sym_lookup, api_sym_update): Ditto. + * interpret.h (r_interpret): Ditto. + * main.c (arg_assign): Ditto. + (main): Reset current_namespace after parsing. + * symbol.c (lookup): New second parameter, do_qualify. Use it + to qualify names or not. + (install): Call fix_up_namespace. + (is_all_upper): New helper routine. + (fix_up_namespace): New function. + +2017-06-13 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (awk_namespace, current_namespace): Move to const char. + (SRCFILE): Add namespace element. + * awkgram.y (awk_namespace, current_namespace): Move to const char. + (set_namespace): New function. + [Grammer]: Call it. + (tokentab): Add "namespace" entry. + (include_source): Push the current namespace. + (next_sourcefile): Pop the current namespace. + (yylex): Add lint warning if a reserved word is used as a namespace + name. + (validate_qualified_name): Make it an error to use a reserved + word as the second part of a fully qualified name. + +2017-06-11 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h (awk_namespace, current_namespace): Declare. + (opcodeval): Add Op_K_namespace. + * awkgram.y (awk_namespace, current_namespace): Define. + (LEX_NAMESPACE): Add lexing and parsing of `@namespace directive'. + (tokentab): Add "namespace" entry. + (yylex): Check if first part of qualified identifier is + a reserved word or function. + * eval.c (optypetab): Add Op_K_namespace. + +2017-06-06 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (yylex): Allow :: in identifiers (the "NAME" token). + Use validate_qualified_name to check it. + (validate_qualified_name): New function. + +2017-05-30 Arnold D. Robbins <arnold@skeeve.com> + + * awkgram.y (nextc): Force -e chunks to be syntactic units. + Needed for namespaces to work correctly. + 2017-05-30 Arnold D. Robbins <arnold@skeeve.com> * NEWS: Mention PROCINFO["argv"]. @@ -1760,6 +2347,10 @@ * dfa.c: Sync with GNULIB. Twice in one day. + Unrelated: Start improving profiling comments for switch/case. + + * awkgram.y (switch_head): New production. + 2016-11-21 Arnold D. Robbins <arnold@skeeve.com> * dfa.c: Sync with GNULIB. @@ -4330,6 +4921,7 @@ * configure.ac: Add an option to enable locale letters in identifiers. Undocumented and subject to being rescinded at any time in the future. + * awkgram.y (is_alpha): Actual code is here. * NEWS: Mention to look at configure --help. Unrelated: diff --git a/ChangeLog.0 b/ChangeLog.0 index 794e0351..d8a13ce5 100644 --- a/ChangeLog.0 +++ b/ChangeLog.0 @@ -7020,7 +7020,7 @@ Tue Dec 4 17:54:30 2001 Arnold D. Robbins <arnold@skeeve.com> * configure.in (AC_ARG_WITH): Add appropriate code for autoconf. * accondig.h (USE_INCLUDED_STRFTIME): Add #undef for it. - * custom.h (USE_INCLUDED_STRFTIME): Set things up write. + * custom.h (USE_INCLUDED_STRFTIME): Set things up right. Tue Dec 4 16:44:07 2001 Andreas Buening <andreas.buening@nexgo.de> @@ -5,6 +5,33 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. +Changes from 4.2.x to 5.0.0 +--------------------------- + +1. The undocumented configure option and code that enabled the use of + non-English "letters" in identifiers is now gone. + +2. The `--with-whiny-user-strftime' configuration option is now gone. + +3. The code now makes some stronger assumptions about a C99 environment. + +4. PROCINFO["platform"] yields a string indicating the platform for + which gawk was compiled. + +5. Writing to elements of SYMTAB that are not variable names now + causes a fatal error. + +6. Comment handling in the pretty-printer has been reworked almost completely + from scratch. As a result, comments in many corner cases that were + previously lost are now included in the formatted output. + +7. Namespaces have been implemented! See the manual. One consequence of this + is that file included with -i, read with -f, and command line program + segments must all be self-contained syntactic units. E.g., you can no + longer do something like this: + + gawk -e 'BEGIN {' -e 'print "hello" }' + Changes from 4.2.1 to 4.2.2 --------------------------- @@ -1,4 +1,4 @@ -Mon Jul 3 21:05:03 IDT 2017 +Wed Dec 12 21:29:16 IST 2018 ============================ There were too many files tracking different thoughts and ideas for @@ -24,8 +24,6 @@ Minor Cleanups and Code Improvements Consider removing use of and/or need for the protos.h file. - Recheck if gnulib regex can be dropped in - Fully synchronize whitespace tests (for \s, \S in Unicode environment) with those of GNU grep. @@ -90,21 +88,6 @@ Things To Think About That May Never Happen Try running with diehard. See http://www.diehard-software.org, https://github.com/emeryberger/DieHard - Implement namespaces. Arnold suggested the following in an email: - - Extend the definition of an 'identifier' to include "." as a valid - character although an identifier can't start with it. - - Extension libraries install functions and global variables with names - that have a "." in them: XML.parse(), XML.name, whatever. - - Awk code can read/write such variables and call such functions, - but they cannot define such functions - function XML.foo() { .. } # error - or create a variable with such a name if it doesn't exist. This would - be a run-time error, not a parse-time error. - - This last rule may be too restrictive. - I don't want to get into fancy rules a la perl and file-scope visibility - etc, I'd like to keep things simple. But how we design this is going - to be very important. - Include a sample rpm spec file in a new packaging subdirectory. (Really needed?) @@ -37,10 +37,10 @@ static char indent_char[] = " "; static NODE **null_lookup(NODE *symbol, NODE *subs); static NODE **null_dump(NODE *symbol, NODE *subs); -static afunc_t null_array_func[] = { +static const array_funcs_t null_array_func = { + "null", (afunc_t) 0, (afunc_t) 0, - null_length, null_lookup, null_afunc, null_afunc, @@ -53,23 +53,20 @@ static afunc_t null_array_func[] = { #define MAX_ATYPE 10 -static afunc_t *array_types[MAX_ATYPE]; +static const array_funcs_t *array_types[MAX_ATYPE]; static int num_array_types = 0; -/* array func to index mapping */ -#define AFUNC(F) (F ## _ind) - /* register_array_func --- add routines to handle arrays */ -int -register_array_func(afunc_t *afunc) +static int +register_array_func(const array_funcs_t *afunc) { if (afunc && num_array_types < MAX_ATYPE) { - if (afunc != str_array_func && ! afunc[AFUNC(atypeof)]) + if (afunc != & str_array_func && afunc->type_of == NULL) return false; array_types[num_array_types++] = afunc; - if (afunc[AFUNC(ainit)]) /* execute init routine if any */ - (void) (*afunc[AFUNC(ainit)])(NULL, NULL); + if (afunc->init) /* execute init routine if any */ + (void) (*afunc->init)(NULL, NULL); return true; } return false; @@ -81,10 +78,10 @@ register_array_func(afunc_t *afunc) void array_init() { - (void) register_array_func(str_array_func); /* the default */ + (void) register_array_func(& str_array_func); /* the default */ if (! do_mpfr) { - (void) register_array_func(int_array_func); - (void) register_array_func(cint_array_func); + (void) register_array_func(& int_array_func); + (void) register_array_func(& cint_array_func); } } @@ -98,7 +95,7 @@ make_array() getnode(array); memset(array, '\0', sizeof(NODE)); array->type = Node_var_array; - array->array_funcs = null_array_func; + array->array_funcs = & null_array_func; /* vname, flags, and parent_array not set here */ return array; @@ -111,7 +108,7 @@ void null_array(NODE *symbol) { symbol->type = Node_var_array; - symbol->array_funcs = null_array_func; + symbol->array_funcs = & null_array_func; symbol->buckets = NULL; symbol->table_size = symbol->array_size = 0; symbol->array_capacity = 0; @@ -129,7 +126,7 @@ static NODE ** null_lookup(NODE *symbol, NODE *subs) { int i; - afunc_t *afunc = NULL; + const array_funcs_t *afunc = NULL; assert(symbol->table_size == 0); @@ -139,7 +136,7 @@ null_lookup(NODE *symbol, NODE *subs) */ for (i = num_array_types - 1; i >= 1; i--) { afunc = array_types[i]; - if (afunc[AFUNC(atypeof)](symbol, subs) != NULL) + if (afunc->type_of(symbol, subs) != NULL) break; } if (i == 0 || afunc == NULL) @@ -150,15 +147,6 @@ null_lookup(NODE *symbol, NODE *subs) return symbol->alookup(symbol, subs); } -/* null_length --- default function for array length interface */ - -NODE ** -null_length(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) -{ - static NODE *tmp; - tmp = symbol; - return & tmp; -} /* null_afunc --- default function for array interface */ @@ -618,6 +606,9 @@ do_delete(NODE *symbol, int nsubs) (void) assoc_remove(symbol, subs); DEREF(subs); + if (assoc_empty(symbol)) + /* last element was removed, so reset array type to null */ + null_array(symbol); #undef free_subs } @@ -1305,7 +1296,7 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt) cmp_func = sort_funcs[qi].comp_func; assoc_kind = sort_funcs[qi].kind; - if (symbol->array_funcs != cint_array_func) + if (symbol->array_funcs != & cint_array_func) assoc_kind &= ~(AASC|ADESC); if (sort_ctxt != SORTED_IN || (assoc_kind & AVALUE) != 0) { @@ -1326,7 +1317,7 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt) if (sp == sort_str || *sp != '\0') fatal(_("`%s' is invalid as a function name"), sort_str); - f = lookup(sort_str); + f = lookup(sort_str, false); if (f == NULL || f->type != Node_func) fatal(_("sort comparison function `%s' is not defined"), sort_str); @@ -49,9 +49,7 @@ #include <stdio.h> #include <assert.h> -#ifdef HAVE_LIMITS_H #include <limits.h> -#endif /* HAVE_LIMITS_H */ #include <ctype.h> #include <setjmp.h> @@ -71,11 +69,8 @@ #endif #endif -#if defined(HAVE_STDARG_H) #include <stdarg.h> -#else -#error "gawk no longer supports <varargs.h>. Please update your compiler and runtime" -#endif +#include <stdbool.h> #include <signal.h> #include <time.h> #include <errno.h> @@ -87,11 +82,6 @@ extern int errno; #include <stdlib.h> #endif /* not STDC_HEADERS */ -#ifdef HAVE_STDBOOL_H -#include <stdbool.h> -#else -#include "missing_d/gawkbool.h" -#endif /* We can handle multibyte strings. */ #include <wchar.h> @@ -306,6 +296,12 @@ typedef union bucket_item { } hi; } BUCKET; +enum commenttype { + EOL_COMMENT = 1, + BLOCK_COMMENT, + FOR_COMMENT // special case +}; + /* string hash table */ #define ahnext hs.next #define ahname hs.name /* a string index node */ @@ -324,6 +320,19 @@ struct exp_instruction; typedef int (*Func_print)(FILE *, const char *, ...); typedef struct exp_node **(*afunc_t)(struct exp_node *, struct exp_node *); +typedef struct { + const char *name; + afunc_t init; + afunc_t type_of; /* avoid reserved word typeof */ + afunc_t lookup; + afunc_t exists; + afunc_t clear; + afunc_t remove; + afunc_t list; + afunc_t copy; + afunc_t dump; + afunc_t store; +} array_funcs_t; /* * NOTE - this struct is a rather kludgey -- it is packed to minimize @@ -336,7 +345,7 @@ typedef struct exp_node { struct exp_node *lptr; struct exp_instruction *li; long ll; - afunc_t *lp; + const array_funcs_t *lp; } l; union { struct exp_node *rptr; @@ -350,6 +359,7 @@ typedef struct exp_node { struct exp_node *extra; void (*aptr)(void); long xl; + void *cmnt; // used by pretty printer } x; char *name; size_t reserved; @@ -378,6 +388,7 @@ typedef struct exp_node { wchar_t *wsp; size_t wslen; struct exp_node *typre; + enum commenttype comtype; } val; } sub; NODETYPE type; @@ -542,29 +553,16 @@ typedef struct exp_node { #define xarray sub.nodep.rn #define parent_array sub.nodep.x.extra -#define ainit array_funcs[0] -#define ainit_ind 0 -#define atypeof array_funcs[1] -#define atypeof_ind 1 -#define alength array_funcs[2] -#define alength_ind 2 -#define alookup array_funcs[3] -#define alookup_ind 3 -#define aexists array_funcs[4] -#define aexists_ind 4 -#define aclear array_funcs[5] -#define aclear_ind 5 -#define aremove array_funcs[6] -#define aremove_ind 6 -#define alist array_funcs[7] -#define alist_ind 7 -#define acopy array_funcs[8] -#define acopy_ind 8 -#define adump array_funcs[9] -#define adump_ind 9 -#define astore array_funcs[10] -#define astore_ind 10 -#define NUM_AFUNCS 11 /* # of entries in array_funcs */ +#define ainit array_funcs->init +#define atypeof array_funcs->type_of +#define alookup array_funcs->lookup +#define aexists array_funcs->exists +#define aclear array_funcs->clear +#define aremove array_funcs->remove +#define alist array_funcs->list +#define acopy array_funcs->copy +#define adump array_funcs->dump +#define astore array_funcs->store /* Node_array_ref: */ #define orig_array lnode @@ -575,9 +573,7 @@ typedef struct exp_node { #define alevel sub.nodep.x.xl /* Op_comment */ -#define comment_type sub.val.idx -#define EOL_COMMENT 1 -#define FULL_COMMENT 2 +#define comment_type sub.val.comtype /* --------------------------------lint warning types----------------------------*/ typedef enum lintvals { @@ -673,6 +669,7 @@ typedef enum opcodeval { Op_K_getline_redir, Op_K_getline, Op_K_nextfile, + Op_K_namespace, Op_builtin, Op_sub_builtin, /* sub, gsub and gensub */ @@ -774,6 +771,7 @@ typedef struct exp_instruction { awk_ext_func_t *exf; } x; + struct exp_instruction *comment; short source_line; short pool_size; // memory management in symbol.c OPCODE opcode; @@ -924,6 +922,9 @@ typedef struct exp_instruction { #define condpair_left d.di #define condpair_right x.xi +/* Op_Rule, Op_Func */ +#define ns_name d.name + /* Op_store_var */ #define initval x.xn @@ -1019,11 +1020,13 @@ typedef struct srcfile { char *lexeme; char *lexptr_begin; int lasttok; + INSTRUCTION *comment; /* comment on @load line */ + const char *namespace; } SRCFILE; // structure for INSTRUCTION pool, needed mainly for debugger typedef struct instruction_pool { -#define MAX_INSTRUCTION_ALLOC 3 // we don't call bcalloc with more than this +#define MAX_INSTRUCTION_ALLOC 4 // we don't call bcalloc with more than this struct instruction_mem_pool { struct instruction_block *block_list; INSTRUCTION *free_space; // free location in active block @@ -1119,9 +1122,9 @@ extern NODE *(*format_val)(const char *, int, NODE *); extern int (*cmp_numbers)(const NODE *, const NODE *); /* built-in array types */ -extern afunc_t str_array_func[]; -extern afunc_t cint_array_func[]; -extern afunc_t int_array_func[]; +extern const array_funcs_t str_array_func; +extern const array_funcs_t cint_array_func; +extern const array_funcs_t int_array_func; /* special node used to indicate success in array routines (not NULL) */ extern NODE *success_node; @@ -1206,6 +1209,10 @@ extern char envsep; extern char casetable[]; /* for case-independent regexp matching */ +extern const char awk_namespace[]; /* "awk" */ +extern const char *current_namespace; +extern bool namespace_changed; + /* ------------------------- Runtime stack -------------------------------- */ typedef union stack_item { @@ -1345,7 +1352,7 @@ DEREF(NODE *r) extern jmp_buf fatal_tag; extern int fatal_tag_valid; -#define assoc_length(a) ((*((a)->alength(a, NULL)))->table_size) +#define assoc_length(a) ((a)->table_size) #define assoc_empty(a) (assoc_length(a) == 0) #define assoc_lookup(a, s) ((a)->alookup(a, s)) @@ -1377,8 +1384,6 @@ extern NODE *force_array(NODE *symbol, bool canfatal); extern const char *make_aname(const NODE *symbol); extern const char *array_vname(const NODE *symbol); extern void array_init(void); -extern int register_array_func(afunc_t *afunc); -extern NODE **null_length(NODE *symbol, NODE *subs); extern NODE **null_afunc(NODE *symbol, NODE *subs); extern void set_SUBSEP(void); extern NODE *concat_exp(int nargs, bool do_subsep); @@ -1400,7 +1405,7 @@ extern int parse_program(INSTRUCTION **pcode); extern void track_ext_func(const char *name); extern void dump_funcs(void); extern void dump_vars(const char *fname); -extern const char *getfname(NODE *(*)(int)); +extern const char *getfname(NODE *(*)(int), bool prepend_awk); extern NODE *stopme(int nargs); extern void shadow_funcs(void); extern int check_special(const char *name); @@ -1417,6 +1422,7 @@ extern bool is_alnum(int c); extern bool is_letter(int c); extern bool is_identchar(int c); extern NODE *make_regnode(int type, NODE *exp); +extern bool validate_qualified_name(char *token); /* builtin.c */ extern double double_to_int(double d); extern NODE *do_exp(int nargs); @@ -1507,9 +1513,10 @@ extern NODE *do_ext(int nargs); void load_ext(const char *lib_name); /* temporary */ extern void close_extensions(void); #ifdef DYNAMIC -extern awk_bool_t make_builtin(const awk_ext_func_t *); +extern awk_bool_t make_builtin(const char *name_space, const awk_ext_func_t *); extern NODE *get_argument(int); extern NODE *get_actual_argument(NODE *, int, bool); +extern bool is_valid_identifier(const char *name); #define get_scalar_argument(n, i) get_actual_argument((n), (i), false) #define get_array_argument(n, i) get_actual_argument((n), (i), true) #endif @@ -1705,7 +1712,7 @@ extern NODE *remove_symbol(NODE *r); extern void destroy_symbol(NODE *r); extern void release_symbols(NODE *symlist, int keep_globals); extern void append_symbol(NODE *r); -extern NODE *lookup(const char *name); +extern NODE *lookup(const char *name, bool do_qualify); extern NODE *make_params(char **pnames, int pcount); extern void install_params(NODE *func); extern void remove_params(NODE *func); @@ -96,11 +96,31 @@ static int isnoeffect(OPCODE type); static INSTRUCTION *make_assignable(INSTRUCTION *ip); static void dumpintlstr(const char *str, size_t len); static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2); -static int include_source(INSTRUCTION *file); -static int load_library(INSTRUCTION *file); +static bool include_source(INSTRUCTION *file, void **srcfile_p); +static bool load_library(INSTRUCTION *file, void **srcfile_p); +static void set_namespace(INSTRUCTION *ns, INSTRUCTION *comment); static void next_sourcefile(void); static char *tokexpand(void); static NODE *set_profile_text(NODE *n, const char *str, size_t len); +static int check_qualified_special(char *token); +static INSTRUCTION *trailing_comment; +static INSTRUCTION *outer_comment; +static INSTRUCTION *interblock_comment; +static INSTRUCTION *pending_comment; +static INSTRUCTION *namespace_chain; + +#ifdef DEBUG_COMMENTS +static void +debug_print_comment_s(const char *name, INSTRUCTION *comment, int line) +{ + if (comment != NULL) + fprintf(stderr, "%d: %s: <%.*s>\n", line, name, + (int) (comment->memory->stlen - 1), + comment->memory->stptr); +} +#define debug_print_comment(comment) \ + debug_print_comment_s(# comment, comment, __LINE__) +#endif #define instruction(t) bcalloc(t, 1, 0) @@ -127,8 +147,8 @@ 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 void check_comment(void); +static void merge_comments(INSTRUCTION *c1, INSTRUCTION *c2); +static INSTRUCTION *make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace); static void add_sign_to_num(NODE *n, char sign); static bool at_seen = false; @@ -185,6 +205,10 @@ extern INSTRUCTION *rule_list; extern int max_args; extern NODE **args_array; +const char awk_namespace[] = "awk"; +const char *current_namespace = awk_namespace; +bool namespace_changed = false; + static INSTRUCTION *rule_block[sizeof(ruletab)]; static INSTRUCTION *ip_rec; @@ -195,27 +219,16 @@ static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; INSTRUCTION *main_beginfile; -static INSTRUCTION *comment = NULL; -static INSTRUCTION *prior_comment = NULL; -static INSTRUCTION *comment_to_save = NULL; -static INSTRUCTION *program_comment = NULL; -static INSTRUCTION *function_comment = NULL; -static INSTRUCTION *block_comment = NULL; - -static bool func_first = true; -static bool first_rule = 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); static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2); -static inline INSTRUCTION *add_pending_comment(INSTRUCTION *stmt); extern double fmod(double x, double y); #define YYSTYPE INSTRUCTION * -#line 219 "awkgram.c" /* yacc.c:338 */ +#line 232 "awkgram.c" /* yacc.c:338 */ # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -299,9 +312,10 @@ extern int yydebug; LEX_INCLUDE = 304, LEX_EVAL = 305, LEX_LOAD = 306, - NEWLINE = 307, - SLASH_BEFORE_EQUAL = 308, - UNARY = 309 + LEX_NAMESPACE = 307, + NEWLINE = 308, + SLASH_BEFORE_EQUAL = 309, + UNARY = 310 }; #endif /* Tokens. */ @@ -354,9 +368,10 @@ extern int yydebug; #define LEX_INCLUDE 304 #define LEX_EVAL 305 #define LEX_LOAD 306 -#define NEWLINE 307 -#define SLASH_BEFORE_EQUAL 308 -#define UNARY 309 +#define LEX_NAMESPACE 307 +#define NEWLINE 308 +#define SLASH_BEFORE_EQUAL 309 +#define UNARY 310 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED @@ -605,21 +620,21 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 1236 +#define YYLAST 1191 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 76 +#define YYNTOKENS 77 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 70 +#define YYNNTS 71 /* YYNRULES -- Number of rules. */ -#define YYNRULES 203 +#define YYNRULES 207 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 350 +#define YYNSTATES 355 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 309 +#define YYMAXUTOK 310 #define YYTRANSLATE(YYX) \ ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -631,16 +646,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 64, 2, 2, 67, 63, 2, 2, - 68, 69, 61, 59, 56, 60, 2, 62, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 55, 75, - 57, 2, 58, 54, 70, 2, 2, 2, 2, 2, + 2, 2, 2, 65, 2, 2, 68, 64, 2, 2, + 69, 70, 62, 60, 57, 61, 2, 63, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 56, 76, + 58, 2, 59, 55, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 71, 2, 72, 66, 2, 2, 2, 2, 2, + 2, 72, 2, 73, 67, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 73, 2, 74, 2, 2, 2, 2, + 2, 2, 2, 74, 2, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -658,34 +673,35 @@ static const yytype_uint8 yytranslate[] = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 65 + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 66 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 215, 215, 217, 222, 223, 227, 239, 244, 255, - 262, 268, 277, 285, 287, 292, 300, 302, 308, 316, - 326, 356, 370, 384, 392, 403, 415, 417, 419, 425, - 433, 434, 438, 438, 484, 483, 517, 532, 534, 539, - 549, 596, 601, 602, 606, 608, 610, 617, 707, 749, - 791, 904, 911, 918, 929, 939, 949, 959, 971, 988, - 987, 1001, 1013, 1013, 1112, 1112, 1146, 1177, 1186, 1187, - 1193, 1194, 1201, 1206, 1218, 1232, 1234, 1242, 1249, 1251, - 1259, 1268, 1270, 1279, 1280, 1288, 1293, 1293, 1306, 1310, - 1318, 1319, 1322, 1324, 1329, 1330, 1339, 1340, 1345, 1350, - 1359, 1361, 1363, 1370, 1371, 1377, 1378, 1383, 1385, 1390, - 1392, 1400, 1405, 1414, 1415, 1420, 1422, 1427, 1429, 1437, - 1442, 1450, 1451, 1456, 1463, 1467, 1469, 1471, 1484, 1501, - 1511, 1518, 1520, 1525, 1527, 1529, 1537, 1539, 1544, 1546, - 1551, 1553, 1555, 1612, 1614, 1616, 1618, 1620, 1622, 1624, - 1626, 1640, 1645, 1650, 1675, 1681, 1683, 1685, 1687, 1689, - 1691, 1696, 1700, 1732, 1740, 1746, 1752, 1765, 1766, 1767, - 1772, 1777, 1781, 1785, 1800, 1821, 1826, 1863, 1892, 1893, - 1899, 1900, 1905, 1907, 1914, 1931, 1948, 1950, 1957, 1962, - 1970, 1980, 1992, 2001, 2005, 2009, 2013, 2017, 2021, 2024, - 2026, 2030, 2034, 2038 + 0, 230, 230, 231, 236, 246, 250, 262, 270, 284, + 295, 305, 315, 328, 338, 340, 345, 355, 357, 362, + 364, 366, 372, 376, 381, 411, 423, 435, 441, 450, + 468, 470, 472, 478, 486, 487, 491, 491, 525, 524, + 558, 573, 575, 580, 581, 601, 606, 607, 611, 622, + 627, 634, 742, 793, 843, 969, 990, 1011, 1021, 1031, + 1041, 1052, 1065, 1083, 1082, 1096, 1114, 1114, 1212, 1212, + 1245, 1275, 1283, 1284, 1290, 1291, 1298, 1303, 1316, 1331, + 1333, 1341, 1348, 1350, 1358, 1367, 1369, 1378, 1379, 1387, + 1392, 1392, 1405, 1411, 1423, 1427, 1449, 1450, 1456, 1457, + 1466, 1467, 1472, 1477, 1494, 1496, 1498, 1505, 1506, 1512, + 1513, 1518, 1520, 1527, 1529, 1537, 1542, 1553, 1554, 1559, + 1561, 1568, 1570, 1578, 1583, 1593, 1594, 1599, 1606, 1610, + 1612, 1614, 1627, 1644, 1654, 1661, 1663, 1668, 1670, 1672, + 1680, 1682, 1687, 1689, 1694, 1696, 1698, 1755, 1757, 1759, + 1761, 1763, 1765, 1767, 1769, 1783, 1788, 1793, 1818, 1824, + 1826, 1828, 1830, 1832, 1834, 1839, 1843, 1875, 1883, 1889, + 1895, 1908, 1909, 1910, 1915, 1920, 1924, 1928, 1943, 1964, + 1969, 2006, 2048, 2049, 2055, 2056, 2061, 2063, 2070, 2087, + 2104, 2106, 2113, 2118, 2126, 2136, 2148, 2157, 2161, 2166, + 2170, 2174, 2178, 2183, 2184, 2188, 2192, 2196 }; #endif @@ -703,17 +719,18 @@ static const char *const yytname[] = "LEX_NEXT", "LEX_EXIT", "LEX_FUNCTION", "LEX_BEGINFILE", "LEX_ENDFILE", "LEX_GETLINE", "LEX_NEXTFILE", "LEX_IN", "LEX_AND", "LEX_OR", "INCREMENT", "DECREMENT", "LEX_BUILTIN", "LEX_LENGTH", "LEX_EOF", - "LEX_INCLUDE", "LEX_EVAL", "LEX_LOAD", "NEWLINE", "SLASH_BEFORE_EQUAL", - "'?'", "':'", "','", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", - "'!'", "UNARY", "'^'", "'$'", "'('", "')'", "'@'", "'['", "']'", "'{'", - "'}'", "';'", "$accept", "program", "rule", "source", "library", - "pattern", "action", "func_name", "lex_builtin", "function_prologue", - "$@1", "regexp", "$@2", "typed_regexp", "a_slash", "statements", - "statement_term", "statement", "non_compound_stmt", "$@3", "simple_stmt", - "$@4", "$@5", "opt_simple_stmt", "case_statements", "case_statement", - "case_value", "print", "print_expression_list", "output_redir", "$@6", - "if_statement", "nls", "opt_nls", "input_redir", "opt_param_list", - "param_list", "opt_exp", "opt_expression_list", "expression_list", + "LEX_INCLUDE", "LEX_EVAL", "LEX_LOAD", "LEX_NAMESPACE", "NEWLINE", + "SLASH_BEFORE_EQUAL", "'?'", "':'", "','", "'<'", "'>'", "'+'", "'-'", + "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'", "'('", "')'", "'@'", + "'['", "']'", "'{'", "'}'", "';'", "$accept", "program", "rule", + "source", "library", "namespace", "pattern", "action", "func_name", + "lex_builtin", "function_prologue", "$@1", "regexp", "$@2", + "typed_regexp", "a_slash", "statements", "statement_term", "statement", + "non_compound_stmt", "$@3", "simple_stmt", "$@4", "$@5", + "opt_simple_stmt", "case_statements", "case_statement", "case_value", + "print", "print_expression_list", "output_redir", "$@6", "if_statement", + "nls", "opt_nls", "input_redir", "opt_param_list", "param_list", + "opt_exp", "opt_expression_list", "expression_list", "opt_fcall_expression_list", "fcall_expression_list", "fcall_exp", "exp", "assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp", "simp_exp_nc", "non_post_simp_exp", "func_call", "direct_func_call", @@ -734,61 +751,62 @@ static const yytype_uint16 yytoknum[] = 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 63, 58, 44, 60, 62, 43, - 45, 42, 47, 37, 33, 309, 94, 36, 40, 41, - 64, 91, 93, 123, 125, 59 + 305, 306, 307, 308, 309, 63, 58, 44, 60, 62, + 43, 45, 42, 47, 37, 33, 310, 94, 36, 40, + 41, 64, 91, 93, 123, 125, 59 }; # endif -#define YYPACT_NINF -275 +#define YYPACT_NINF -283 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-275))) + (!!((Yystate) == (-283))) -#define YYTABLE_NINF -115 +#define YYTABLE_NINF -119 #define yytable_value_is_error(Yytable_value) \ - (!!((Yytable_value) == (-115))) + (!!((Yytable_value) == (-119))) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { - -275, 376, -275, -275, -12, -9, -275, -275, -275, -275, - 171, -275, -275, 44, 44, 44, 5, 40, -275, -275, - -275, 1139, 1139, -275, 1139, 1166, 869, 27, -275, -18, - 2, -275, -275, 89, 884, 1065, 192, 214, -275, -275, - -275, -275, 248, 795, 869, -275, 10, -275, -275, -275, - -275, -275, 116, 82, -275, 115, -275, -275, -275, 795, - 795, 166, 107, 104, 107, 107, 1139, 117, -275, -275, - 15, 349, 23, 45, -275, 125, -275, -275, -275, 89, - -275, 125, -275, 178, -275, -275, 1092, 172, 1139, 1139, - 1139, 125, -275, -275, -275, 1139, 146, 192, 1139, 1139, - 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, - -275, 181, -275, -275, 173, 1139, -275, -275, -275, 128, - 73, -275, 1107, 14, 1107, -275, -275, -275, -275, 1139, - -275, 128, 128, 349, -275, -275, -275, 1139, 125, -275, - 152, 916, -275, -275, 16, 92, -275, 20, 92, 89, - -275, 599, -275, -275, -275, 148, -275, 124, 22, 1048, - 1139, 199, 44, 265, 265, 107, 107, 107, 107, 265, - 265, 107, 107, 107, 107, -275, -275, 1107, -275, 1092, - 842, -275, 43, 192, -275, -275, 1107, -275, 172, -275, - 1107, -275, -275, -275, -275, -275, 133, -275, 41, 144, - 145, 125, 147, 92, 92, -275, -275, 92, 1139, 92, - 125, -275, -275, 92, -275, -275, 1107, -275, 151, 125, - 1139, 1107, -275, -275, -275, -275, -275, -275, 128, 76, - -275, 1139, 1139, -275, 224, 1139, 1139, 715, 949, -275, - -275, -275, 92, 1107, -275, -275, -275, 646, 599, 125, - -275, -275, 1107, 125, -275, 49, 349, 92, -9, 160, - 349, 349, 206, 113, -275, 151, -275, 869, 225, -275, - 169, -275, -275, -275, -275, -275, 125, -275, -275, 11, - -275, -275, -275, 125, 125, 179, 172, 125, 15, -275, - -275, 715, -275, -275, 2, 715, 1139, 128, 762, 152, - 1139, 219, -275, -275, 349, 125, 275, 125, 1065, 125, - 112, 125, 715, 125, 997, 715, -275, 261, 205, -275, - 191, -275, -275, 997, 128, -275, -275, -275, 271, 272, - -275, -275, 205, -275, 125, -275, 128, 125, -275, -275, - 125, -275, 125, 715, -275, 449, 715, -275, 524, -275 + -283, 316, -283, -283, -45, -28, -283, -283, -283, -283, + 160, -283, -283, 23, 23, 23, -39, -18, -283, -283, + -283, 1047, 1047, -283, 1047, 1075, 818, 257, -283, 99, + -20, -283, -283, 11, 1017, 974, 378, 415, -283, -283, + -283, -283, 329, 742, 818, -283, 0, -283, -283, -283, + -283, -283, 25, 9, -283, 22, -283, -283, -283, 742, + 742, 79, 46, 18, 46, 46, 1047, 114, -283, -283, + 13, 286, 44, 47, 60, -283, 94, -283, -283, -283, + 11, -283, 94, -283, 151, -283, -283, 1002, 162, 1047, + 1047, 1047, 94, -283, -283, -283, 1047, 1047, 132, 378, + 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, + 1047, 1047, -283, 170, -283, -283, 168, 1047, -283, -283, + -283, 116, 14, -283, 1132, 76, 1132, -283, -283, -283, + -283, 1047, -283, 116, 116, 286, -283, -283, -283, 1047, + -283, 144, 846, -283, -283, 34, 91, -283, 39, 91, + -283, 59, 91, 11, -283, 542, -283, -283, -283, 145, + -283, 135, 580, 1113, -283, 189, 1132, 23, 230, 230, + 46, 46, 46, 46, 230, 230, 46, 46, 46, 46, + -283, -283, 1132, -283, 1002, 770, -283, 27, 378, -283, + -283, 1132, 162, -283, 1132, -283, -283, -283, -283, -283, + -283, -283, 119, -283, 12, 123, 126, 94, 128, 91, + 91, -283, -283, 91, 1047, 91, 94, -283, -283, 91, + -283, -283, 1132, -283, 122, 94, 1047, -283, -283, -283, + -283, -283, -283, 116, 73, -283, 1047, 1047, -283, 198, + 1047, 1047, 660, 895, -283, -283, -283, 91, 1132, -283, + -283, -283, 590, 542, 94, -283, -283, 1132, 94, -283, + 28, 286, 91, -28, 141, 286, 286, 190, -23, -283, + 122, -283, 818, 205, -283, 325, -283, -283, -283, -283, + -283, 94, -283, -283, 115, -283, -283, -283, 94, 94, + 153, 162, 94, 13, -283, -283, 660, -283, -283, -20, + 660, 1047, 116, 694, 144, 1047, 209, -283, -283, 286, + 94, 1090, 94, 974, 94, 152, 94, 660, 94, 929, + 660, -283, 342, 176, -283, 158, -283, -283, 929, 116, + -283, -283, -283, 236, 243, -283, -283, 176, -283, 94, + -283, 116, 94, -283, -283, 94, -283, 94, 660, -283, + 390, 660, -283, 466, -283 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -796,65 +814,68 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 2, 0, 1, 6, 0, 189, 171, 172, 21, 22, - 0, 23, 24, 178, 0, 0, 0, 166, 5, 90, - 38, 0, 0, 37, 0, 0, 0, 0, 3, 0, - 0, 161, 34, 4, 19, 132, 140, 141, 143, 167, - 175, 191, 168, 0, 0, 186, 0, 190, 27, 26, - 30, 31, 0, 0, 28, 94, 179, 169, 170, 0, - 0, 0, 174, 168, 173, 162, 0, 195, 168, 109, - 0, 107, 0, 0, 176, 92, 201, 7, 8, 42, - 39, 92, 9, 0, 91, 136, 0, 0, 0, 0, - 0, 92, 137, 139, 138, 0, 0, 142, 0, 0, + 2, 0, 1, 6, 0, 193, 175, 176, 25, 26, + 0, 27, 28, 182, 0, 0, 0, 170, 5, 94, + 42, 0, 0, 41, 0, 0, 0, 0, 3, 0, + 0, 165, 38, 4, 23, 136, 144, 145, 147, 171, + 179, 195, 172, 0, 0, 190, 0, 194, 31, 30, + 34, 35, 0, 0, 32, 98, 183, 173, 174, 0, + 0, 0, 178, 172, 177, 166, 0, 199, 172, 113, + 0, 111, 0, 0, 0, 180, 96, 205, 7, 8, + 46, 43, 96, 9, 0, 95, 140, 0, 0, 0, + 0, 0, 96, 141, 143, 142, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 134, 133, 151, 152, 0, 0, 117, 36, 122, 0, - 0, 115, 121, 0, 107, 188, 187, 29, 32, 0, - 150, 0, 0, 0, 193, 194, 192, 110, 92, 198, - 0, 0, 163, 14, 0, 0, 17, 0, 0, 93, - 196, 0, 43, 35, 127, 128, 129, 125, 126, 0, - 0, 130, 178, 148, 149, 145, 146, 147, 144, 159, - 160, 156, 157, 158, 155, 124, 135, 123, 177, 118, - 0, 185, 0, 95, 164, 165, 111, 203, 0, 112, - 108, 13, 10, 16, 11, 41, 0, 59, 0, 0, - 0, 92, 0, 0, 0, 81, 82, 0, 103, 0, - 92, 40, 53, 0, 62, 46, 67, 39, 199, 92, - 0, 20, 154, 119, 120, 116, 100, 98, 0, 0, - 153, 0, 103, 64, 0, 0, 0, 0, 68, 54, - 55, 56, 0, 104, 57, 197, 61, 0, 0, 92, - 200, 44, 131, 92, 101, 0, 0, 0, 180, 0, - 0, 0, 0, 189, 69, 0, 58, 0, 85, 83, - 0, 45, 25, 33, 102, 99, 92, 60, 65, 0, - 182, 184, 66, 92, 92, 0, 0, 92, 0, 86, - 63, 0, 181, 183, 0, 0, 0, 0, 0, 84, - 0, 88, 70, 48, 0, 92, 0, 92, 87, 92, - 0, 92, 0, 92, 68, 0, 72, 0, 0, 71, - 0, 49, 50, 68, 0, 89, 75, 78, 0, 0, - 79, 80, 0, 202, 92, 47, 0, 92, 77, 76, - 92, 39, 92, 0, 39, 0, 0, 52, 0, 51 + 0, 0, 138, 137, 155, 156, 0, 0, 121, 40, + 126, 0, 0, 119, 125, 0, 111, 192, 191, 33, + 36, 0, 154, 0, 0, 0, 197, 198, 196, 114, + 202, 0, 0, 167, 15, 0, 0, 18, 0, 0, + 21, 0, 0, 97, 200, 0, 47, 39, 131, 132, + 133, 129, 130, 0, 207, 134, 24, 182, 152, 153, + 149, 150, 151, 148, 163, 164, 160, 161, 162, 159, + 128, 139, 127, 181, 122, 0, 189, 0, 99, 168, + 169, 115, 0, 116, 112, 14, 10, 17, 11, 20, + 12, 45, 0, 63, 0, 0, 0, 96, 0, 0, + 0, 85, 86, 0, 107, 0, 96, 44, 57, 0, + 66, 50, 71, 43, 203, 96, 0, 158, 123, 124, + 120, 104, 102, 0, 0, 157, 0, 107, 68, 0, + 0, 0, 0, 72, 58, 59, 60, 0, 108, 61, + 201, 65, 0, 0, 96, 204, 48, 135, 96, 105, + 0, 0, 0, 184, 0, 0, 0, 0, 193, 73, + 0, 62, 0, 89, 87, 0, 49, 29, 37, 106, + 103, 96, 64, 69, 0, 186, 188, 70, 96, 96, + 0, 0, 96, 0, 90, 67, 0, 185, 187, 0, + 0, 0, 0, 0, 88, 0, 92, 74, 52, 0, + 96, 0, 96, 91, 96, 0, 96, 0, 96, 72, + 0, 76, 0, 0, 75, 0, 53, 54, 72, 0, + 93, 79, 82, 0, 0, 83, 84, 0, 206, 96, + 51, 0, 96, 81, 80, 96, 43, 96, 0, 43, + 0, 0, 56, 0, 55 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -275, -275, -275, -275, -275, -275, 252, -275, -275, -275, - -275, -33, -275, -80, -275, -213, 100, -144, -275, -275, - -231, -275, -275, -274, -275, -275, -275, -275, -275, -275, - -275, -275, 7, 62, -275, -275, -275, 54, -275, -43, - 1, -275, -23, -1, -275, -275, -275, -13, 17, -275, - 263, -275, 8, 127, -275, -275, 21, -36, -275, -275, - -78, -2, -275, -27, -230, -65, -275, -15, -38, -94 + -283, -283, -283, -283, -283, -283, -283, 226, -283, -283, + -283, -283, -63, -283, -77, -283, -215, -73, -30, -283, + -283, -234, -283, -283, -282, -283, -283, -283, -283, -283, + -283, -283, -283, 5, -35, -283, -283, -283, 24, -283, + -43, 101, -283, -15, -1, -283, -283, -283, -40, 17, + -283, 237, -283, -6, 96, -283, -283, -16, -42, -283, + -283, -81, -2, -283, -27, -186, -65, -283, -62, -68, + -8 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 1, 28, 145, 148, 29, 77, 53, 54, 30, - 182, 31, 83, 118, 32, 151, 78, 211, 212, 232, - 213, 247, 258, 265, 310, 319, 332, 214, 268, 290, - 300, 215, 149, 150, 130, 228, 229, 242, 269, 70, - 119, 120, 121, 216, 115, 94, 95, 35, 36, 37, - 38, 39, 40, 55, 278, 279, 280, 45, 46, 47, - 41, 42, 136, 217, 218, 142, 249, 219, 334, 141 + -1, 1, 28, 146, 149, 152, 29, 78, 53, 54, + 30, 187, 31, 84, 120, 32, 155, 79, 217, 218, + 237, 219, 252, 263, 270, 315, 324, 337, 220, 273, + 295, 305, 221, 153, 154, 132, 233, 234, 247, 274, + 70, 121, 122, 123, 222, 117, 95, 96, 35, 36, + 37, 38, 39, 40, 55, 283, 284, 285, 45, 46, + 47, 41, 42, 138, 223, 224, 143, 254, 82, 339, + 142 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -862,351 +883,344 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 34, 123, 80, 80, 248, 140, 154, 264, 33, 156, - 126, 56, 57, 58, 81, 137, 137, 191, 271, 63, - 63, 193, 63, 68, 143, 71, 180, 125, 292, 144, - 4, 175, 85, 63, 19, 74, 79, 86, 62, 64, - 324, 65, 122, 124, 226, 233, 146, 227, 5, 336, - 274, 147, 97, 275, 178, 75, 43, 76, 122, 122, - 131, 132, 44, 87, 88, 133, 184, 185, -12, 74, - 138, 138, -15, 59, 179, 75, 72, 254, 73, 92, - 93, 44, 44, 264, 139, 155, 181, 157, 158, 159, - 335, -12, 264, 262, 161, -15, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 60, 234, - 230, 25, -96, 316, 177, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 63, 345, 138, - 81, 348, 138, 81, 85, 255, 186, 317, 318, 86, - 190, 84, -114, 152, 19, -97, 183, 301, 112, 113, - 128, 303, 79, 160, 286, 79, 223, 225, 85, 221, - 56, 134, 135, 253, 19, 87, 127, 76, 322, 4, - 137, 325, 129, 103, 48, 49, 5, 19, 122, 122, - -106, 92, 93, 153, 44, 162, -92, 176, 81, 81, - 117, 276, 81, 188, 81, 283, 284, 139, 81, 347, - 187, 231, 349, 250, 270, 92, 93, 243, 297, -115, - 79, 79, 235, 236, 79, 238, 79, 50, 51, 252, - 79, -106, 281, 299, 288, 138, 76, 81, 259, 282, - 256, 243, 305, 285, 260, 261, 289, 331, -106, 311, - 309, 52, 81, 281, -106, 192, 124, 296, 194, 79, - 287, 98, 99, 100, 101, 102, -115, -115, 103, 337, - 333, 110, 111, 237, 79, 210, 71, 302, 326, 327, - 117, 342, 245, 104, 105, 106, 107, 108, 338, 339, - 109, 251, 82, 307, 330, 85, 257, 308, 67, 222, - 86, 313, 112, 113, 340, 304, 0, 306, 63, 0, - 293, 114, 0, 239, 240, 0, 63, 241, 0, 244, - 0, 272, 0, 246, 20, 273, 87, 88, 89, 0, - 328, 329, 0, 23, 0, 97, 100, 101, 102, 90, - 0, 103, 92, 93, 0, 0, 0, 0, 291, 0, - 0, 0, 266, 0, 0, 294, 295, 0, 0, 298, - 76, 0, 0, 0, 0, 0, 0, 277, 0, 85, - 0, 0, 0, 0, 86, 0, 0, 312, 0, 314, - 0, 315, 320, 321, 0, 323, 2, 3, 0, 4, - 5, 0, 0, 6, 7, 0, 0, 0, 0, 0, - 87, 88, 89, 0, 8, 9, 341, 0, 0, 343, - 0, 0, 344, 90, 346, 0, 92, 93, 0, 0, - 0, 0, 10, 11, 12, 13, 0, 0, 139, 0, - 14, 15, 16, 17, 18, 0, 0, 0, 19, 20, - 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, - 24, 0, 0, 25, 26, 0, 27, 0, 0, -18, - 195, -18, 4, 5, 0, 0, 6, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, - 0, 197, 198, 199, -74, -74, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 0, 0, 0, 13, 209, - 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, - 0, -74, 20, 0, 0, 0, 0, 0, 21, 22, - 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, - 0, 0, 75, -74, 76, 195, 0, 4, 5, 0, - 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 196, 0, 197, 198, 199, -73, - -73, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 0, 0, 0, 13, 209, 0, 0, 0, 14, 15, - 16, 17, 0, 0, 0, 0, -73, 20, 0, 0, - 0, 0, 0, 21, 22, 0, 23, 0, 24, 0, - 0, 25, 26, 0, 61, 0, 0, 75, -73, 76, - 195, 0, 4, 5, 0, 0, 6, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, - 0, 197, 198, 199, 0, 0, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 0, 0, 0, 13, 209, - 0, 0, 0, 14, 15, 16, 17, 69, 0, 4, - 5, 0, 20, 6, 7, 0, 0, -105, 21, 22, - 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, - 0, 0, 75, 210, 76, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 14, 15, 16, 17, 0, 0, 0, 0, -105, 20, - 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, - 24, 0, 0, 25, 267, -105, 61, 0, 4, 5, - 0, -105, 6, 7, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 196, 0, 197, 198, 199, - 0, 0, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 0, 0, 0, 13, 209, 0, 0, 0, 14, - 15, 16, 17, 0, 0, 4, 5, 0, 20, 6, - 7, 0, 0, 0, 21, 22, 0, 23, 0, 24, - 0, 0, 25, 26, 0, 61, 0, 0, 75, 0, - 76, 0, 0, 0, 0, 0, 116, 0, 4, 5, - 0, 13, 6, 7, 117, 0, 14, 15, 16, 17, - 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, - 0, 21, 22, 0, 23, 0, 24, 0, 0, 25, - 26, 0, 61, 0, 13, 0, 0, 76, 0, 14, - 15, 16, 17, 224, 0, 4, 5, 0, 20, 6, - 7, 117, 0, 0, 21, 22, 0, 23, 0, 24, - 0, 0, 25, 26, -113, 61, 0, 0, 0, 0, - 69, 0, 4, 5, 0, 0, 6, 7, 0, 0, + 34, 125, 81, 81, 128, 141, 33, 160, 253, 269, + 158, 56, 57, 58, 139, 184, 238, 127, 291, 63, + 63, 75, 63, 68, 43, 71, 97, 5, 231, 279, + 59, 232, 280, 63, 80, 195, 180, 329, 62, 64, + 197, 65, 124, 126, 44, 144, 341, 156, 147, 44, + 145, 60, 99, 148, 76, 75, 183, 164, 124, 124, + 199, 150, 114, 115, 85, 135, 151, 276, 189, 190, + 92, 92, 44, 196, 259, 129, 198, 139, 130, 200, + 131, 239, 4, 140, -118, 269, 159, -13, 161, 162, + 163, 25, -16, 225, 269, 165, 166, -100, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + -13, 235, -19, 105, 185, -16, 182, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 63, + 92, 350, 297, 92, 353, -19, 244, 245, 191, 340, + 246, 194, 249, -101, 19, 86, 251, 19, 188, 186, + 87, 80, 19, 321, 80, 86, 157, 80, 136, 137, + 133, 134, 255, 48, 49, 56, 5, 77, 258, 228, + 230, 167, 242, 76, 271, 77, 88, 322, 323, 119, + 225, 250, 181, 124, 124, 192, 140, 44, 236, 282, + 256, 225, 240, 93, 94, 241, 281, 243, 77, -119, + 288, 289, 264, 93, 94, 19, 50, 51, 292, 275, + 302, 287, 267, 248, 80, 80, 294, 290, 80, 277, + 80, 286, 301, 278, 80, 257, 260, -96, 304, 293, + 314, 52, 338, 216, 225, 261, 248, 310, 225, 265, + 266, 312, 286, 343, 316, 336, 296, -119, -119, 318, + 344, 126, 80, 299, 300, 225, 83, 303, 225, 335, + 4, 262, 67, 227, 342, 313, 306, 80, 298, 345, + 308, 71, 307, 0, 0, 317, 347, 319, 0, 320, + 325, 326, 0, 328, 0, 0, 225, 327, 225, 225, + 330, 225, 102, 103, 104, 0, 86, 105, 0, 0, + 309, 87, 311, 63, 346, 0, 72, 348, 73, 74, + 349, 63, 351, 0, 0, 0, 2, 3, 352, 4, + 5, 354, 0, 6, 7, 0, 139, 88, 89, 90, + 99, 0, 0, 0, 8, 9, -110, 0, 0, 0, + 0, 91, 112, 113, 93, 94, 0, 0, 0, 331, + 332, 119, 10, 11, 12, 13, 140, 0, 0, 0, + 14, 15, 16, 17, 18, 0, 0, 0, 0, 19, + 20, 0, 0, 114, 115, 0, 21, 22, -110, 23, + 0, 24, 92, 116, 25, 26, 0, 27, 0, 0, + -22, 201, -22, 4, 5, -110, 20, 6, 7, 0, + 0, -110, 333, 334, 0, 23, 0, 0, 0, 0, + 202, 0, 203, 204, 205, -78, -78, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 0, 0, 0, 13, + 215, 0, 0, 0, 14, 15, 16, 17, 100, 101, + 102, 103, 104, -78, 20, 105, 0, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 26, + 0, 61, 0, 0, 76, -78, 77, 201, 0, 4, + 5, 0, 0, 6, 7, 106, 107, 108, 109, 110, + 0, 0, 111, 0, 0, 0, 202, 0, 203, 204, + 205, -77, -77, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 0, 0, 0, 13, 215, 0, 0, 0, + 14, 15, 16, 17, 0, 0, 0, 0, 0, -77, + 20, 0, 0, 0, 0, 0, 21, 22, 0, 23, + 0, 24, 0, 0, 25, 26, 0, 61, 0, 0, + 76, -77, 77, 201, 0, 4, 5, 0, 0, 6, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 202, 0, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 0, 0, + 0, 13, 215, 0, 0, 0, 14, 15, 16, 17, + 86, 69, 0, 4, 5, 87, 20, 6, 7, 0, + 0, -109, 21, 22, 0, 23, 0, 24, 0, 0, + 25, 26, 0, 61, 0, 0, 76, 216, 77, 0, + 0, 88, 89, 0, 0, 0, 0, 0, 0, 13, + 0, 0, 0, 0, 14, 15, 16, 17, 93, 94, + 0, 0, 0, -109, 20, 0, 0, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 272, + -109, 61, 0, 4, 5, 0, -109, 6, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 202, 0, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 0, 4, 5, 13, + 215, 6, 7, 0, 14, 15, 16, 17, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 26, + 0, 61, 0, 13, 76, 0, 77, 0, 14, 15, + 16, 17, 0, 118, 0, 4, 5, 0, 20, 6, + 7, 119, 0, 0, 21, 22, 0, 23, 0, 24, + 0, 0, 25, 26, 0, 61, 0, 0, 0, 0, + 77, 229, 0, 4, 5, 0, 0, 6, 7, 119, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, - 0, 0, 0, 0, 85, 20, 0, 0, 0, 86, - 0, 21, 22, 0, 23, 0, 24, 0, 13, 25, - 26, 0, 61, 14, 15, 16, 17, 189, 0, 4, - 5, 0, 20, 6, 7, 87, 88, 89, 21, 22, - 0, 23, 0, 24, 0, 0, 25, 26, 90, 61, - 91, 92, 93, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 263, 0, 13, 6, 7, 0, 0, - 14, 15, 16, 17, 0, 0, 0, 0, 0, 20, - 0, 0, 198, 0, 0, 21, 22, 0, 23, 0, - 24, 205, 206, 25, 26, 0, 61, 0, 13, 0, - 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, - 4, 5, 20, 0, 6, 7, 0, 0, 21, 22, - 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, - 198, 0, 0, 0, 0, 0, 0, 0, 0, 205, - 206, 0, 0, 0, 0, 0, 13, 0, 0, 0, - 0, 14, 15, 16, 17, 0, 0, 0, 0, 0, - 20, 0, 0, 0, 0, 0, 21, 22, 85, 23, - 0, 24, 0, 86, 25, 26, 0, 61, 4, 5, - 0, 0, 6, 7, 0, 0, 0, 96, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, - 88, 89, 0, 0, 0, 4, 5, 0, 0, 6, - 7, 117, 90, 220, 13, 92, 93, 0, 0, 14, - 15, 16, 17, 0, 0, 0, 0, 85, 20, 0, - 0, 0, 86, 0, 21, 22, 0, 23, 0, 24, - 0, 13, 25, 26, 0, 61, 14, 15, 16, 17, - 0, 0, 4, 5, 0, 20, 6, 7, 87, 88, - 89, 21, 22, 0, 23, 0, 24, 0, 0, 25, - 26, 90, 61, 0, 92, 93, 0, 0, 0, 4, - 5, 0, 0, 6, 7, 0, 0, 0, 13, 0, - 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, + 0, 0, 21, 22, 0, 23, 0, 24, 0, 13, + 25, 26, -117, 61, 14, 15, 16, 17, 0, 69, + 0, 4, 5, 0, 20, 6, 7, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 26, + 0, 61, 0, 0, 0, 0, 0, 193, 0, 4, + 5, 0, 0, 6, 7, 0, 0, 13, 0, 0, + 0, 0, 14, 15, 16, 17, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 21, 22, - 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, - 14, 15, 16, 17, 0, 0, 0, 0, 0, 20, - 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, - 24, 0, 0, 25, 66, 0, 61 + 0, 23, 0, 24, 0, 13, 25, 26, 0, 61, + 14, 15, 16, 17, 0, 0, 0, 0, 4, 268, + 20, 0, 6, 7, 0, 0, 21, 22, 0, 23, + 0, 24, 0, 0, 25, 26, 0, 61, 204, 0, + 0, 0, 0, 0, 0, 0, 0, 211, 212, 0, + 0, 0, 4, 5, 13, 0, 6, 7, 0, 14, + 15, 16, 17, 0, 0, 0, 0, 0, 0, 20, + 0, 0, 204, 0, 0, 21, 22, 0, 23, 0, + 24, 211, 212, 25, 26, 0, 61, 0, 13, 0, + 0, 0, 0, 14, 15, 16, 17, 4, 5, 0, + 0, 6, 7, 20, 0, 0, 98, 0, 0, 21, + 22, 0, 23, 0, 24, 0, 0, 25, 26, 0, + 61, 0, 0, 0, 0, 4, 5, 0, 0, 6, + 7, 119, 0, 13, 0, 0, 0, 0, 14, 15, + 16, 17, 0, 0, 0, 0, 0, 86, 20, 0, + 0, 0, 87, 0, 21, 22, 0, 23, 0, 24, + 0, 13, 25, 26, 0, 61, 14, 15, 16, 17, + 4, 5, 0, 0, 6, 7, 20, 0, 88, 89, + 90, 0, 21, 22, 0, 23, 0, 24, 0, 0, + 25, 26, 91, 61, 92, 93, 94, 0, 4, 5, + 0, 0, 6, 7, 0, 0, 13, 0, 0, 0, + 0, 14, 15, 16, 17, 0, 0, 0, 0, 0, + 86, 20, 0, 0, 0, 87, 0, 21, 22, 0, + 23, 0, 24, 0, 0, 25, 26, 0, 61, 14, + 15, 16, 17, 86, 0, 0, 0, 0, 87, 20, + 0, 88, 89, 90, 0, 21, 22, 0, 23, 0, + 24, 0, 86, 25, 66, 91, 61, 87, 93, 94, + 0, 0, 0, 0, 88, 89, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 0, 91, 226, + 0, 93, 94, 88, 89, 90, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, + 93, 94 }; static const yytype_int16 yycheck[] = { - 1, 44, 29, 30, 217, 70, 86, 238, 1, 87, - 46, 13, 14, 15, 29, 1, 1, 1, 248, 21, - 22, 1, 24, 25, 1, 26, 120, 17, 17, 6, - 3, 111, 10, 35, 52, 27, 29, 15, 21, 22, - 314, 24, 43, 44, 1, 4, 1, 4, 4, 323, - 1, 6, 35, 4, 119, 73, 68, 75, 59, 60, - 59, 60, 71, 41, 42, 66, 131, 132, 52, 61, - 56, 56, 52, 68, 1, 73, 49, 1, 51, 57, - 58, 71, 71, 314, 69, 86, 72, 88, 89, 90, - 320, 75, 323, 237, 95, 75, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 68, 68, - 188, 67, 69, 1, 115, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 129, 341, 56, - 145, 344, 56, 148, 10, 229, 137, 25, 26, 15, - 141, 52, 69, 81, 52, 69, 129, 291, 44, 45, - 68, 295, 145, 91, 41, 148, 179, 180, 10, 160, - 162, 44, 45, 228, 52, 41, 50, 75, 312, 3, - 1, 315, 57, 66, 3, 4, 4, 52, 179, 180, - 11, 57, 58, 5, 71, 39, 74, 14, 203, 204, - 9, 256, 207, 41, 209, 260, 261, 69, 213, 343, - 138, 68, 346, 218, 247, 57, 58, 208, 286, 10, - 203, 204, 68, 68, 207, 68, 209, 46, 47, 220, - 213, 52, 258, 288, 267, 56, 75, 242, 4, 69, - 231, 232, 297, 27, 235, 236, 11, 317, 69, 304, - 21, 70, 257, 279, 75, 145, 247, 68, 148, 242, - 265, 59, 60, 61, 62, 63, 57, 58, 66, 324, - 55, 13, 14, 201, 257, 74, 267, 294, 7, 8, - 9, 336, 210, 59, 60, 61, 62, 63, 7, 7, - 66, 219, 30, 298, 317, 10, 232, 300, 25, 162, - 15, 306, 44, 45, 332, 296, -1, 298, 300, -1, - 279, 53, -1, 203, 204, -1, 308, 207, -1, 209, - -1, 249, -1, 213, 53, 253, 41, 42, 43, -1, - 59, 60, -1, 62, -1, 308, 61, 62, 63, 54, - -1, 66, 57, 58, -1, -1, -1, -1, 276, -1, - -1, -1, 242, -1, -1, 283, 284, -1, -1, 287, - 75, -1, -1, -1, -1, -1, -1, 257, -1, 10, - -1, -1, -1, -1, 15, -1, -1, 305, -1, 307, - -1, 309, 310, 311, -1, 313, 0, 1, -1, 3, - 4, -1, -1, 7, 8, -1, -1, -1, -1, -1, - 41, 42, 43, -1, 18, 19, 334, -1, -1, 337, - -1, -1, 340, 54, 342, -1, 57, 58, -1, -1, - -1, -1, 36, 37, 38, 39, -1, -1, 69, -1, - 44, 45, 46, 47, 48, -1, -1, -1, 52, 53, - -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, - 64, -1, -1, 67, 68, -1, 70, -1, -1, 73, - 1, 75, 3, 4, -1, -1, 7, 8, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, - -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, -1, -1, -1, 39, 40, - -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, - -1, 52, 53, -1, -1, -1, -1, -1, 59, 60, - -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, - -1, -1, 73, 74, 75, 1, -1, 3, 4, -1, - -1, 7, 8, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 20, -1, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - -1, -1, -1, 39, 40, -1, -1, -1, 44, 45, - 46, 47, -1, -1, -1, -1, 52, 53, -1, -1, - -1, -1, -1, 59, 60, -1, 62, -1, 64, -1, - -1, 67, 68, -1, 70, -1, -1, 73, 74, 75, - 1, -1, 3, 4, -1, -1, 7, 8, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, - -1, 22, 23, 24, -1, -1, 27, 28, 29, 30, - 31, 32, 33, 34, 35, -1, -1, -1, 39, 40, - -1, -1, -1, 44, 45, 46, 47, 1, -1, 3, - 4, -1, 53, 7, 8, -1, -1, 11, 59, 60, - -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, - -1, -1, 73, 74, 75, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, - 44, 45, 46, 47, -1, -1, -1, -1, 52, 53, - -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, - 64, -1, -1, 67, 68, 69, 70, -1, 3, 4, - -1, 75, 7, 8, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 20, -1, 22, 23, 24, - -1, -1, 27, 28, 29, 30, 31, 32, 33, 34, - 35, -1, -1, -1, 39, 40, -1, -1, -1, 44, - 45, 46, 47, -1, -1, 3, 4, -1, 53, 7, - 8, -1, -1, -1, 59, 60, -1, 62, -1, 64, - -1, -1, 67, 68, -1, 70, -1, -1, 73, -1, - 75, -1, -1, -1, -1, -1, 1, -1, 3, 4, - -1, 39, 7, 8, 9, -1, 44, 45, 46, 47, - -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, - -1, 59, 60, -1, 62, -1, 64, -1, -1, 67, - 68, -1, 70, -1, 39, -1, -1, 75, -1, 44, - 45, 46, 47, 1, -1, 3, 4, -1, 53, 7, - 8, 9, -1, -1, 59, 60, -1, 62, -1, 64, - -1, -1, 67, 68, 69, 70, -1, -1, -1, -1, - 1, -1, 3, 4, -1, -1, 7, 8, -1, -1, - -1, 39, -1, -1, -1, -1, 44, 45, 46, 47, - -1, -1, -1, -1, 10, 53, -1, -1, -1, 15, - -1, 59, 60, -1, 62, -1, 64, -1, 39, 67, - 68, -1, 70, 44, 45, 46, 47, 1, -1, 3, - 4, -1, 53, 7, 8, 41, 42, 43, 59, 60, - -1, 62, -1, 64, -1, -1, 67, 68, 54, 70, - 56, 57, 58, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3, 4, -1, 39, 7, 8, -1, -1, + 1, 44, 29, 30, 46, 70, 1, 88, 223, 243, + 87, 13, 14, 15, 1, 1, 4, 17, 41, 21, + 22, 27, 24, 25, 69, 26, 34, 4, 1, 1, + 69, 4, 4, 35, 29, 1, 113, 319, 21, 22, + 1, 24, 43, 44, 72, 1, 328, 82, 1, 72, + 6, 69, 35, 6, 74, 61, 121, 92, 59, 60, + 1, 1, 44, 45, 53, 66, 6, 253, 133, 134, + 57, 57, 72, 146, 1, 50, 149, 1, 69, 152, + 58, 69, 3, 70, 70, 319, 87, 53, 89, 90, + 91, 68, 53, 155, 328, 96, 97, 70, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 76, 192, 53, 67, 122, 76, 117, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 131, + 57, 346, 17, 57, 349, 76, 209, 210, 139, 325, + 213, 142, 215, 70, 53, 10, 219, 53, 131, 73, + 15, 146, 53, 1, 149, 10, 5, 152, 44, 45, + 59, 60, 224, 3, 4, 167, 4, 76, 233, 184, + 185, 39, 207, 74, 247, 76, 41, 25, 26, 9, + 242, 216, 14, 184, 185, 41, 70, 72, 69, 262, + 225, 253, 69, 58, 59, 69, 261, 69, 76, 10, + 265, 266, 4, 58, 59, 53, 46, 47, 270, 252, + 291, 70, 242, 214, 209, 210, 11, 27, 213, 254, + 215, 263, 69, 258, 219, 226, 234, 75, 293, 272, + 21, 71, 56, 75, 296, 236, 237, 302, 300, 240, + 241, 303, 284, 7, 309, 322, 281, 58, 59, 311, + 7, 252, 247, 288, 289, 317, 30, 292, 320, 322, + 3, 237, 25, 167, 329, 305, 296, 262, 284, 337, + 300, 272, 299, -1, -1, 310, 341, 312, -1, 314, + 315, 316, -1, 318, -1, -1, 348, 317, 350, 351, + 320, 353, 62, 63, 64, -1, 10, 67, -1, -1, + 301, 15, 303, 305, 339, -1, 49, 342, 51, 52, + 345, 313, 347, -1, -1, -1, 0, 1, 348, 3, + 4, 351, -1, 7, 8, -1, 1, 41, 42, 43, + 313, -1, -1, -1, 18, 19, 11, -1, -1, -1, + -1, 55, 13, 14, 58, 59, -1, -1, -1, 7, + 8, 9, 36, 37, 38, 39, 70, -1, -1, -1, + 44, 45, 46, 47, 48, -1, -1, -1, -1, 53, + 54, -1, -1, 44, 45, -1, 60, 61, 53, 63, + -1, 65, 57, 54, 68, 69, -1, 71, -1, -1, + 74, 1, 76, 3, 4, 70, 54, 7, 8, -1, + -1, 76, 60, 61, -1, 63, -1, -1, -1, -1, + 20, -1, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, -1, -1, -1, 39, + 40, -1, -1, -1, 44, 45, 46, 47, 60, 61, + 62, 63, 64, 53, 54, 67, -1, -1, -1, -1, + 60, 61, -1, 63, -1, 65, -1, -1, 68, 69, + -1, 71, -1, -1, 74, 75, 76, 1, -1, 3, + 4, -1, -1, 7, 8, 60, 61, 62, 63, 64, + -1, -1, 67, -1, -1, -1, 20, -1, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, -1, -1, -1, 39, 40, -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, -1, -1, 53, - -1, -1, 23, -1, -1, 59, 60, -1, 62, -1, - 64, 32, 33, 67, 68, -1, 70, -1, 39, -1, - -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, - 3, 4, 53, -1, 7, 8, -1, -1, 59, 60, - -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, - 23, -1, -1, -1, -1, -1, -1, -1, -1, 32, - 33, -1, -1, -1, -1, -1, 39, -1, -1, -1, + 54, -1, -1, -1, -1, -1, 60, 61, -1, 63, + -1, 65, -1, -1, 68, 69, -1, 71, -1, -1, + 74, 75, 76, 1, -1, 3, 4, -1, -1, 7, + 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 20, -1, 22, 23, 24, -1, -1, 27, + 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, + -1, 39, 40, -1, -1, -1, 44, 45, 46, 47, + 10, 1, -1, 3, 4, 15, 54, 7, 8, -1, + -1, 11, 60, 61, -1, 63, -1, 65, -1, -1, + 68, 69, -1, 71, -1, -1, 74, 75, 76, -1, + -1, 41, 42, -1, -1, -1, -1, -1, -1, 39, + -1, -1, -1, -1, 44, 45, 46, 47, 58, 59, + -1, -1, -1, 53, 54, -1, -1, -1, -1, -1, + 60, 61, -1, 63, -1, 65, -1, -1, 68, 69, + 70, 71, -1, 3, 4, -1, 76, 7, 8, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 20, -1, 22, 23, 24, -1, -1, 27, 28, 29, + 30, 31, 32, 33, 34, 35, -1, 3, 4, 39, + 40, 7, 8, -1, 44, 45, 46, 47, -1, -1, + -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, + 60, 61, -1, 63, -1, 65, -1, -1, 68, 69, + -1, 71, -1, 39, 74, -1, 76, -1, 44, 45, + 46, 47, -1, 1, -1, 3, 4, -1, 54, 7, + 8, 9, -1, -1, 60, 61, -1, 63, -1, 65, + -1, -1, 68, 69, -1, 71, -1, -1, -1, -1, + 76, 1, -1, 3, 4, -1, -1, 7, 8, 9, + -1, 39, -1, -1, -1, -1, 44, 45, 46, 47, + -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, + -1, -1, 60, 61, -1, 63, -1, 65, -1, 39, + 68, 69, 70, 71, 44, 45, 46, 47, -1, 1, + -1, 3, 4, -1, 54, 7, 8, -1, -1, -1, + 60, 61, -1, 63, -1, 65, -1, -1, 68, 69, + -1, 71, -1, -1, -1, -1, -1, 1, -1, 3, + 4, -1, -1, 7, 8, -1, -1, 39, -1, -1, + -1, -1, 44, 45, 46, 47, -1, -1, -1, -1, + -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, + -1, 63, -1, 65, -1, 39, 68, 69, -1, 71, + 44, 45, 46, 47, -1, -1, -1, -1, 3, 4, + 54, -1, 7, 8, -1, -1, 60, 61, -1, 63, + -1, 65, -1, -1, 68, 69, -1, 71, 23, -1, + -1, -1, -1, -1, -1, -1, -1, 32, 33, -1, + -1, -1, 3, 4, 39, -1, 7, 8, -1, 44, + 45, 46, 47, -1, -1, -1, -1, -1, -1, 54, + -1, -1, 23, -1, -1, 60, 61, -1, 63, -1, + 65, 32, 33, 68, 69, -1, 71, -1, 39, -1, + -1, -1, -1, 44, 45, 46, 47, 3, 4, -1, + -1, 7, 8, 54, -1, -1, 12, -1, -1, 60, + 61, -1, 63, -1, 65, -1, -1, 68, 69, -1, + 71, -1, -1, -1, -1, 3, 4, -1, -1, 7, + 8, 9, -1, 39, -1, -1, -1, -1, 44, 45, + 46, 47, -1, -1, -1, -1, -1, 10, 54, -1, + -1, -1, 15, -1, 60, 61, -1, 63, -1, 65, + -1, 39, 68, 69, -1, 71, 44, 45, 46, 47, + 3, 4, -1, -1, 7, 8, 54, -1, 41, 42, + 43, -1, 60, 61, -1, 63, -1, 65, -1, -1, + 68, 69, 55, 71, 57, 58, 59, -1, 3, 4, + -1, -1, 7, 8, -1, -1, 39, -1, -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, -1, -1, - 53, -1, -1, -1, -1, -1, 59, 60, 10, 62, - -1, 64, -1, 15, 67, 68, -1, 70, 3, 4, - -1, -1, 7, 8, -1, -1, -1, 12, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, - 42, 43, -1, -1, -1, 3, 4, -1, -1, 7, - 8, 9, 54, 55, 39, 57, 58, -1, -1, 44, - 45, 46, 47, -1, -1, -1, -1, 10, 53, -1, - -1, -1, 15, -1, 59, 60, -1, 62, -1, 64, - -1, 39, 67, 68, -1, 70, 44, 45, 46, 47, - -1, -1, 3, 4, -1, 53, 7, 8, 41, 42, - 43, 59, 60, -1, 62, -1, 64, -1, -1, 67, - 68, 54, 70, -1, 57, 58, -1, -1, -1, 3, - 4, -1, -1, 7, 8, -1, -1, -1, 39, -1, - -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, - -1, -1, 53, -1, -1, -1, -1, -1, 59, 60, - -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, - 44, 45, 46, 47, -1, -1, -1, -1, -1, 53, - -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, - 64, -1, -1, 67, 68, -1, 70 + 10, 54, -1, -1, -1, 15, -1, 60, 61, -1, + 63, -1, 65, -1, -1, 68, 69, -1, 71, 44, + 45, 46, 47, 10, -1, -1, -1, -1, 15, 54, + -1, 41, 42, 43, -1, 60, 61, -1, 63, -1, + 65, -1, 10, 68, 69, 55, 71, 15, 58, 59, + -1, -1, -1, -1, 41, 42, 43, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 76, -1, 55, 56, + -1, 58, 59, 41, 42, 43, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, + 58, 59 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 77, 0, 1, 3, 4, 7, 8, 18, 19, - 36, 37, 38, 39, 44, 45, 46, 47, 48, 52, - 53, 59, 60, 62, 64, 67, 68, 70, 78, 81, - 85, 87, 90, 108, 119, 123, 124, 125, 126, 127, - 128, 136, 137, 68, 71, 133, 134, 135, 3, 4, - 46, 47, 70, 83, 84, 129, 137, 137, 137, 68, - 68, 70, 124, 137, 124, 124, 68, 126, 137, 1, - 115, 119, 49, 51, 128, 73, 75, 82, 92, 108, - 139, 143, 82, 88, 52, 10, 15, 41, 42, 43, - 54, 56, 57, 58, 121, 122, 12, 124, 59, 60, - 61, 62, 63, 66, 59, 60, 61, 62, 63, 66, - 13, 14, 44, 45, 53, 120, 1, 9, 89, 116, - 117, 118, 119, 115, 119, 17, 133, 50, 68, 57, - 110, 116, 116, 119, 44, 45, 138, 1, 56, 69, - 141, 145, 141, 1, 6, 79, 1, 6, 80, 108, - 109, 91, 109, 5, 89, 119, 136, 119, 119, 119, - 109, 119, 39, 124, 124, 124, 124, 124, 124, 124, - 124, 124, 124, 124, 124, 89, 14, 119, 141, 1, - 145, 72, 86, 124, 141, 141, 119, 109, 41, 1, - 119, 1, 92, 1, 92, 1, 20, 22, 23, 24, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 40, - 74, 93, 94, 96, 103, 107, 119, 139, 140, 143, - 55, 119, 129, 118, 1, 118, 1, 4, 111, 112, - 136, 68, 95, 4, 68, 68, 68, 109, 68, 92, - 92, 92, 113, 119, 92, 109, 92, 97, 91, 142, - 143, 109, 119, 141, 1, 145, 119, 113, 98, 4, - 119, 119, 93, 4, 96, 99, 92, 68, 104, 114, - 115, 140, 109, 109, 1, 4, 141, 92, 130, 131, - 132, 133, 69, 141, 141, 27, 41, 143, 115, 11, - 105, 109, 17, 132, 109, 109, 68, 136, 109, 141, - 106, 93, 139, 93, 119, 141, 119, 143, 123, 21, - 100, 141, 109, 143, 109, 109, 1, 25, 26, 101, - 109, 109, 93, 109, 99, 93, 7, 8, 59, 60, - 87, 89, 102, 55, 144, 140, 99, 141, 7, 7, - 144, 109, 141, 109, 109, 91, 109, 93, 91, 93 + 0, 78, 0, 1, 3, 4, 7, 8, 18, 19, + 36, 37, 38, 39, 44, 45, 46, 47, 48, 53, + 54, 60, 61, 63, 65, 68, 69, 71, 79, 83, + 87, 89, 92, 110, 121, 125, 126, 127, 128, 129, + 130, 138, 139, 69, 72, 135, 136, 137, 3, 4, + 46, 47, 71, 85, 86, 131, 139, 139, 139, 69, + 69, 71, 126, 139, 126, 126, 69, 128, 139, 1, + 117, 121, 49, 51, 52, 130, 74, 76, 84, 94, + 110, 141, 145, 84, 90, 53, 10, 15, 41, 42, + 43, 55, 57, 58, 59, 123, 124, 147, 12, 126, + 60, 61, 62, 63, 64, 67, 60, 61, 62, 63, + 64, 67, 13, 14, 44, 45, 54, 122, 1, 9, + 91, 118, 119, 120, 121, 117, 121, 17, 135, 50, + 69, 58, 112, 118, 118, 121, 44, 45, 140, 1, + 70, 143, 147, 143, 1, 6, 80, 1, 6, 81, + 1, 6, 82, 110, 111, 93, 111, 5, 91, 121, + 138, 121, 121, 121, 111, 121, 121, 39, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 91, 14, 121, 143, 1, 147, 73, 88, 126, 143, + 143, 121, 41, 1, 121, 1, 94, 1, 94, 1, + 94, 1, 20, 22, 23, 24, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 40, 75, 95, 96, 98, + 105, 109, 121, 141, 142, 145, 56, 131, 120, 1, + 120, 1, 4, 113, 114, 138, 69, 97, 4, 69, + 69, 69, 111, 69, 94, 94, 94, 115, 121, 94, + 111, 94, 99, 93, 144, 145, 111, 121, 143, 1, + 147, 121, 115, 100, 4, 121, 121, 95, 4, 98, + 101, 94, 69, 106, 116, 117, 142, 111, 111, 1, + 4, 143, 94, 132, 133, 134, 135, 70, 143, 143, + 27, 41, 145, 117, 11, 107, 111, 17, 134, 111, + 111, 69, 138, 111, 143, 108, 95, 141, 95, 121, + 143, 121, 145, 125, 21, 102, 143, 111, 145, 111, + 111, 1, 25, 26, 103, 111, 111, 95, 111, 101, + 95, 7, 8, 60, 61, 89, 91, 104, 56, 146, + 142, 101, 143, 7, 7, 146, 111, 143, 111, 111, + 93, 111, 95, 93, 95 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 76, 77, 77, 77, 77, 77, 78, 78, 78, - 78, 78, 79, 79, 79, 80, 80, 80, 81, 81, - 81, 81, 81, 81, 81, 82, 83, 83, 83, 83, - 84, 84, 86, 85, 88, 87, 89, 90, 90, 91, - 91, 91, 92, 92, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 94, 94, 94, 94, 94, 95, - 94, 94, 97, 96, 98, 96, 96, 96, 99, 99, - 100, 100, 100, 101, 101, 102, 102, 102, 102, 102, - 102, 103, 103, 104, 104, 105, 106, 105, 107, 107, - 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, - 112, 112, 112, 113, 113, 114, 114, 115, 115, 115, - 115, 115, 115, 116, 116, 117, 117, 117, 117, 117, - 117, 118, 118, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 120, 120, 120, 121, 121, 122, 122, - 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, - 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, - 125, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 127, 127, 128, 129, 129, - 130, 130, 131, 131, 132, 133, 134, 134, 135, 136, - 136, 137, 137, 138, 138, 138, 139, 140, 141, 142, - 142, 143, 144, 145 + 0, 77, 78, 78, 78, 78, 78, 79, 79, 79, + 79, 79, 79, 80, 80, 80, 81, 81, 81, 82, + 82, 82, 83, 83, 83, 83, 83, 83, 83, 84, + 85, 85, 85, 85, 86, 86, 88, 87, 90, 89, + 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, + 96, 96, 96, 97, 96, 96, 99, 98, 100, 98, + 98, 98, 101, 101, 102, 102, 102, 103, 103, 104, + 104, 104, 104, 104, 104, 105, 105, 106, 106, 107, + 108, 107, 109, 109, 110, 110, 111, 111, 112, 112, + 113, 113, 114, 114, 114, 114, 114, 115, 115, 116, + 116, 117, 117, 117, 117, 117, 117, 118, 118, 119, + 119, 119, 119, 119, 119, 120, 120, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 122, 122, 122, + 123, 123, 124, 124, 125, 125, 125, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, + 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, + 129, 130, 131, 131, 132, 132, 133, 133, 134, 135, + 136, 136, 137, 138, 138, 139, 139, 140, 140, 140, + 141, 142, 143, 144, 144, 145, 146, 147 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, - 4, 4, 1, 2, 1, 1, 2, 1, 0, 1, - 4, 1, 1, 1, 1, 5, 1, 1, 1, 2, - 1, 1, 0, 7, 0, 3, 1, 1, 1, 0, - 2, 2, 1, 2, 2, 3, 1, 9, 6, 8, - 8, 12, 11, 1, 2, 2, 2, 2, 3, 0, - 4, 2, 0, 4, 0, 4, 4, 1, 0, 1, - 0, 2, 2, 5, 4, 1, 2, 2, 1, 1, - 1, 1, 1, 1, 3, 0, 0, 3, 6, 9, - 1, 2, 0, 1, 0, 2, 0, 1, 1, 3, - 1, 2, 3, 0, 1, 0, 1, 1, 3, 1, - 2, 3, 3, 0, 1, 1, 3, 1, 2, 3, - 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, - 3, 5, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 2, 1, 3, 3, 3, 3, 3, 3, - 3, 2, 2, 5, 4, 3, 3, 3, 3, 3, - 3, 1, 2, 3, 4, 4, 1, 1, 1, 2, - 2, 1, 1, 2, 2, 1, 2, 4, 0, 1, - 0, 2, 1, 2, 1, 3, 1, 2, 2, 1, - 2, 1, 3, 1, 1, 0, 2, 2, 1, 0, - 1, 1, 1, 2 + 4, 4, 4, 1, 2, 1, 1, 2, 1, 1, + 2, 1, 0, 1, 3, 1, 1, 1, 1, 5, + 1, 1, 1, 2, 1, 1, 0, 7, 0, 3, + 1, 1, 1, 0, 2, 2, 1, 2, 2, 3, + 1, 9, 6, 8, 8, 12, 11, 1, 2, 2, + 2, 2, 3, 0, 4, 2, 0, 4, 0, 4, + 4, 1, 0, 1, 0, 2, 2, 5, 4, 1, + 2, 2, 1, 1, 1, 1, 1, 1, 3, 0, + 0, 3, 6, 9, 1, 2, 0, 1, 0, 2, + 0, 1, 1, 3, 1, 2, 3, 0, 1, 0, + 1, 1, 3, 1, 2, 3, 3, 0, 1, 1, + 3, 1, 2, 3, 3, 1, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 5, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 2, 1, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 5, 4, 3, + 3, 3, 3, 3, 3, 1, 2, 3, 4, 4, + 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, + 2, 4, 0, 1, 0, 2, 1, 2, 1, 3, + 1, 2, 2, 1, 2, 1, 3, 1, 1, 0, + 2, 2, 1, 0, 1, 1, 1, 2 }; @@ -1882,25 +1896,45 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 3: -#line 218 "awkgram.y" /* yacc.c:1645 */ + case 2: +#line 230 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 1903 "awkgram.c" /* yacc.c:1645 */ + break; + + case 3: +#line 232 "awkgram.y" /* yacc.c:1645 */ { rule = 0; yyerrok; } -#line 1892 "awkgram.c" /* yacc.c:1645 */ +#line 1912 "awkgram.c" /* yacc.c:1645 */ + break; + + case 4: +#line 237 "awkgram.y" /* yacc.c:1645 */ + { + if ((yyvsp[0]) != NULL) { + if ((yyvsp[-1]) == NULL) + outer_comment = (yyvsp[0]); + else + interblock_comment = (yyvsp[0]); + } + (yyval) = (yyvsp[-1]); + } +#line 1926 "awkgram.c" /* yacc.c:1645 */ break; case 5: -#line 224 "awkgram.y" /* yacc.c:1645 */ +#line 247 "awkgram.y" /* yacc.c:1645 */ { next_sourcefile(); } -#line 1900 "awkgram.c" /* yacc.c:1645 */ +#line 1934 "awkgram.c" /* yacc.c:1645 */ break; case 6: -#line 228 "awkgram.y" /* yacc.c:1645 */ +#line 251 "awkgram.y" /* yacc.c:1645 */ { rule = 0; /* @@ -1909,20 +1943,23 @@ yyreduce: */ /* yyerrok; */ } -#line 1913 "awkgram.c" /* yacc.c:1645 */ +#line 1947 "awkgram.c" /* yacc.c:1645 */ break; case 7: -#line 240 "awkgram.y" /* yacc.c:1645 */ +#line 263 "awkgram.y" /* yacc.c:1645 */ { (void) append_rule((yyvsp[-1]), (yyvsp[0])); - first_rule = false; + if (pending_comment != NULL) { + interblock_comment = pending_comment; + pending_comment = NULL; + } } -#line 1922 "awkgram.c" /* yacc.c:1645 */ +#line 1959 "awkgram.c" /* yacc.c:1645 */ break; case 8: -#line 245 "awkgram.y" /* yacc.c:1645 */ +#line 271 "awkgram.y" /* yacc.c:1645 */ { if (rule != Rule) { msg(_("%s blocks must have an action part"), ruletab[rule]); @@ -1930,291 +1967,319 @@ yyreduce: } else if ((yyvsp[-1]) == NULL) { msg(_("each rule must have a pattern or an action part")); errcount++; - } else /* pattern rule with non-empty pattern */ + } else { /* pattern rule with non-empty pattern */ + if ((yyvsp[0]) != NULL) + list_append((yyvsp[-1]), (yyvsp[0])); (void) append_rule((yyvsp[-1]), NULL); + } } -#line 1937 "awkgram.c" /* yacc.c:1645 */ +#line 1977 "awkgram.c" /* yacc.c:1645 */ break; case 9: -#line 256 "awkgram.y" /* yacc.c:1645 */ +#line 285 "awkgram.y" /* yacc.c:1645 */ { in_function = NULL; (void) mk_function((yyvsp[-1]), (yyvsp[0])); want_param_names = DONT_CHECK; + if (pending_comment != NULL) { + interblock_comment = pending_comment; + pending_comment = NULL; + } yyerrok; } -#line 1948 "awkgram.c" /* yacc.c:1645 */ +#line 1992 "awkgram.c" /* yacc.c:1645 */ break; case 10: -#line 263 "awkgram.y" /* yacc.c:1645 */ +#line 296 "awkgram.y" /* yacc.c:1645 */ { want_source = false; at_seen = false; + if ((yyvsp[-1]) != NULL && (yyvsp[0]) != NULL) { + SRCFILE *s = (SRCFILE *) (yyvsp[-1]); + s->comment = (yyvsp[0]); + } yyerrok; } -#line 1958 "awkgram.c" /* yacc.c:1645 */ +#line 2006 "awkgram.c" /* yacc.c:1645 */ break; case 11: -#line 269 "awkgram.y" /* yacc.c:1645 */ +#line 306 "awkgram.y" /* yacc.c:1645 */ { want_source = false; at_seen = false; + if ((yyvsp[-1]) != NULL && (yyvsp[0]) != NULL) { + SRCFILE *s = (SRCFILE *) (yyvsp[-1]); + s->comment = (yyvsp[0]); + } yyerrok; } -#line 1968 "awkgram.c" /* yacc.c:1645 */ +#line 2020 "awkgram.c" /* yacc.c:1645 */ break; case 12: -#line 278 "awkgram.y" /* yacc.c:1645 */ +#line 316 "awkgram.y" /* yacc.c:1645 */ + { + want_source = false; + at_seen = false; + + // this frees $3 storage in all cases + set_namespace((yyvsp[-1]), (yyvsp[0])); + + yyerrok; + } +#line 2034 "awkgram.c" /* yacc.c:1645 */ + break; + + case 13: +#line 329 "awkgram.y" /* yacc.c:1645 */ { - if (include_source((yyvsp[0])) < 0) + void *srcfile = NULL; + + if (! include_source((yyvsp[0]), & srcfile)) YYABORT; efree((yyvsp[0])->lextok); bcfree((yyvsp[0])); - (yyval) = NULL; + (yyval) = (INSTRUCTION *) srcfile; } -#line 1980 "awkgram.c" /* yacc.c:1645 */ +#line 2048 "awkgram.c" /* yacc.c:1645 */ break; - case 13: -#line 286 "awkgram.y" /* yacc.c:1645 */ + case 14: +#line 339 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 1986 "awkgram.c" /* yacc.c:1645 */ +#line 2054 "awkgram.c" /* yacc.c:1645 */ break; - case 14: -#line 288 "awkgram.y" /* yacc.c:1645 */ + case 15: +#line 341 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 1992 "awkgram.c" /* yacc.c:1645 */ +#line 2060 "awkgram.c" /* yacc.c:1645 */ break; - case 15: -#line 293 "awkgram.y" /* yacc.c:1645 */ + case 16: +#line 346 "awkgram.y" /* yacc.c:1645 */ { - if (load_library((yyvsp[0])) < 0) + void *srcfile; + + if (! load_library((yyvsp[0]), & srcfile)) YYABORT; efree((yyvsp[0])->lextok); bcfree((yyvsp[0])); - (yyval) = NULL; + (yyval) = (INSTRUCTION *) srcfile; } -#line 2004 "awkgram.c" /* yacc.c:1645 */ +#line 2074 "awkgram.c" /* yacc.c:1645 */ break; - case 16: -#line 301 "awkgram.y" /* yacc.c:1645 */ + case 17: +#line 356 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 2010 "awkgram.c" /* yacc.c:1645 */ +#line 2080 "awkgram.c" /* yacc.c:1645 */ break; - case 17: -#line 303 "awkgram.y" /* yacc.c:1645 */ + case 18: +#line 358 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 2016 "awkgram.c" /* yacc.c:1645 */ +#line 2086 "awkgram.c" /* yacc.c:1645 */ break; - case 18: -#line 308 "awkgram.y" /* yacc.c:1645 */ + case 19: +#line 363 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); } +#line 2092 "awkgram.c" /* yacc.c:1645 */ + break; + + case 20: +#line 365 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 2098 "awkgram.c" /* yacc.c:1645 */ + break; + + case 21: +#line 367 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 2104 "awkgram.c" /* yacc.c:1645 */ + break; + + case 22: +#line 372 "awkgram.y" /* yacc.c:1645 */ { rule = Rule; - if (comment != NULL) { - (yyval) = list_create(comment); - comment = NULL; - } else - (yyval) = NULL; + (yyval) = NULL; } -#line 2029 "awkgram.c" /* yacc.c:1645 */ +#line 2113 "awkgram.c" /* yacc.c:1645 */ break; - case 19: -#line 317 "awkgram.y" /* yacc.c:1645 */ + case 23: +#line 377 "awkgram.y" /* yacc.c:1645 */ { rule = Rule; - if (comment != NULL) { - (yyval) = list_prepend((yyvsp[0]), comment); - comment = NULL; - } else - (yyval) = (yyvsp[0]); } -#line 2042 "awkgram.c" /* yacc.c:1645 */ +#line 2121 "awkgram.c" /* yacc.c:1645 */ break; - case 20: -#line 327 "awkgram.y" /* yacc.c:1645 */ + case 24: +#line 382 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *tp; - add_lint((yyvsp[-3]), LINT_assign_in_cond); + add_lint((yyvsp[-2]), LINT_assign_in_cond); add_lint((yyvsp[0]), LINT_assign_in_cond); tp = instruction(Op_no_op); - list_prepend((yyvsp[-3]), bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); - (yyvsp[-3])->nexti->triggered = false; - (yyvsp[-3])->nexti->target_jmp = (yyvsp[0])->nexti; + list_prepend((yyvsp[-2]), bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); + (yyvsp[-2])->nexti->triggered = false; + (yyvsp[-2])->nexti->target_jmp = (yyvsp[0])->nexti; - list_append((yyvsp[-3]), instruction(Op_cond_pair)); - (yyvsp[-3])->lasti->line_range = (yyvsp[-3])->nexti; - (yyvsp[-3])->lasti->target_jmp = tp; + list_append((yyvsp[-2]), instruction(Op_cond_pair)); + (yyvsp[-2])->lasti->line_range = (yyvsp[-2])->nexti; + (yyvsp[-2])->lasti->target_jmp = tp; list_append((yyvsp[0]), instruction(Op_cond_pair)); - (yyvsp[0])->lasti->line_range = (yyvsp[-3])->nexti; + (yyvsp[0])->lasti->line_range = (yyvsp[-2])->nexti; (yyvsp[0])->lasti->target_jmp = tp; if (do_pretty_print) { - ((yyvsp[-3])->nexti + 1)->condpair_left = (yyvsp[-3])->lasti; - ((yyvsp[-3])->nexti + 1)->condpair_right = (yyvsp[0])->lasti; + ((yyvsp[-2])->nexti + 1)->condpair_left = (yyvsp[-2])->lasti; + ((yyvsp[-2])->nexti + 1)->condpair_right = (yyvsp[0])->lasti; } - if (comment != NULL) { - (yyval) = list_append(list_merge(list_prepend((yyvsp[-3]), comment), (yyvsp[0])), tp); - comment = NULL; - } else - (yyval) = list_append(list_merge((yyvsp[-3]), (yyvsp[0])), tp); + /* Put any comments in front of the range expression */ + if ((yyvsp[-1]) != NULL) + (yyval) = list_append(list_merge(list_prepend((yyvsp[-2]), (yyvsp[-1])), (yyvsp[0])), tp); + else + (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), tp); rule = Rule; } -#line 2076 "awkgram.c" /* yacc.c:1645 */ +#line 2155 "awkgram.c" /* yacc.c:1645 */ break; - case 21: -#line 357 "awkgram.y" /* yacc.c:1645 */ + case 25: +#line 412 "awkgram.y" /* yacc.c:1645 */ { 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")); (yyvsp[0])->in_rule = rule = BEGIN; (yyvsp[0])->source_file = source; - check_comment(); (yyval) = (yyvsp[0]); } -#line 2094 "awkgram.c" /* yacc.c:1645 */ +#line 2171 "awkgram.c" /* yacc.c:1645 */ break; - case 22: -#line 371 "awkgram.y" /* yacc.c:1645 */ + case 26: +#line 424 "awkgram.y" /* yacc.c:1645 */ { 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")); (yyvsp[0])->in_rule = rule = END; (yyvsp[0])->source_file = source; - check_comment(); (yyval) = (yyvsp[0]); } -#line 2112 "awkgram.c" /* yacc.c:1645 */ +#line 2187 "awkgram.c" /* yacc.c:1645 */ break; - case 23: -#line 385 "awkgram.y" /* yacc.c:1645 */ + case 27: +#line 436 "awkgram.y" /* yacc.c:1645 */ { - func_first = false; (yyvsp[0])->in_rule = rule = BEGINFILE; (yyvsp[0])->source_file = source; - check_comment(); (yyval) = (yyvsp[0]); } -#line 2124 "awkgram.c" /* yacc.c:1645 */ +#line 2197 "awkgram.c" /* yacc.c:1645 */ break; - case 24: -#line 393 "awkgram.y" /* yacc.c:1645 */ + case 28: +#line 442 "awkgram.y" /* yacc.c:1645 */ { - func_first = false; (yyvsp[0])->in_rule = rule = ENDFILE; (yyvsp[0])->source_file = source; - check_comment(); (yyval) = (yyvsp[0]); } -#line 2136 "awkgram.c" /* yacc.c:1645 */ +#line 2207 "awkgram.c" /* yacc.c:1645 */ break; - case 25: -#line 404 "awkgram.y" /* yacc.c:1645 */ + case 29: +#line 451 "awkgram.y" /* yacc.c:1645 */ { - INSTRUCTION *ip; - if ((yyvsp[-3]) == NULL) - ip = list_create(instruction(Op_no_op)); - else - ip = (yyvsp[-3]); + INSTRUCTION *ip = make_braced_statements((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2])); + + if ((yyvsp[-2]) != NULL && (yyvsp[0]) != NULL) { + merge_comments((yyvsp[-2]), (yyvsp[0])); + pending_comment = (yyvsp[-2]); + } else if ((yyvsp[-2]) != NULL) { + pending_comment = (yyvsp[-2]); + } else if ((yyvsp[0]) != NULL) { + pending_comment = (yyvsp[0]); + } + (yyval) = ip; } -#line 2149 "awkgram.c" /* yacc.c:1645 */ +#line 2226 "awkgram.c" /* yacc.c:1645 */ break; - case 26: -#line 416 "awkgram.y" /* yacc.c:1645 */ + case 30: +#line 469 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 2155 "awkgram.c" /* yacc.c:1645 */ +#line 2232 "awkgram.c" /* yacc.c:1645 */ break; - case 27: -#line 418 "awkgram.y" /* yacc.c:1645 */ + case 31: +#line 471 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 2161 "awkgram.c" /* yacc.c:1645 */ +#line 2238 "awkgram.c" /* yacc.c:1645 */ break; - case 28: -#line 420 "awkgram.y" /* yacc.c:1645 */ + case 32: +#line 473 "awkgram.y" /* yacc.c:1645 */ { yyerror(_("`%s' is a built-in function, it cannot be redefined"), tokstart); YYABORT; } -#line 2171 "awkgram.c" /* yacc.c:1645 */ +#line 2248 "awkgram.c" /* yacc.c:1645 */ break; - case 29: -#line 426 "awkgram.y" /* yacc.c:1645 */ + case 33: +#line 479 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); at_seen = false; } -#line 2180 "awkgram.c" /* yacc.c:1645 */ +#line 2257 "awkgram.c" /* yacc.c:1645 */ break; - case 32: -#line 438 "awkgram.y" /* yacc.c:1645 */ + case 36: +#line 491 "awkgram.y" /* yacc.c:1645 */ { want_param_names = FUNC_HEADER; } -#line 2186 "awkgram.c" /* yacc.c:1645 */ +#line 2263 "awkgram.c" /* yacc.c:1645 */ break; - case 33: -#line 439 "awkgram.y" /* yacc.c:1645 */ + case 37: +#line 492 "awkgram.y" /* yacc.c:1645 */ { - /* - * 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 (prior_comment != NULL) { - comment_to_save = prior_comment; - prior_comment = NULL; - } else if (comment != NULL) { - comment_to_save = comment; - comment = NULL; - } else - comment_to_save = NULL; - - if (comment_to_save != NULL && func_first - && strstr(comment_to_save->memory->stptr, "\n\n") != NULL) - split_comment(); - - /* save any other pre-function comment as function comment */ - if (comment_to_save != NULL) { - function_comment = comment_to_save; - comment_to_save = NULL; + INSTRUCTION *func_comment = NULL; + // Merge any comments found in the parameter list with those + // following the function header, associate the whole shebang + // with the function as one block comment. + if ((yyvsp[-2]) != NULL && (yyvsp[-2])->comment != NULL) { + if ((yyvsp[0]) != NULL) { + merge_comments((yyvsp[-2])->comment, (yyvsp[0])); + } + func_comment = (yyvsp[-2])->comment; + } else if ((yyvsp[0]) != NULL) { + func_comment = (yyvsp[0]); } - func_first = false; + (yyvsp[-6])->source_file = source; + (yyvsp[-6])->comment = func_comment; if (install_function((yyvsp[-5])->lextok, (yyvsp[-6]), (yyvsp[-2])) < 0) YYABORT; in_function = (yyvsp[-5])->lextok; @@ -2224,17 +2289,17 @@ yyreduce: (yyval) = (yyvsp[-6]); want_param_names = FUNC_BODY; } -#line 2228 "awkgram.c" /* yacc.c:1645 */ +#line 2293 "awkgram.c" /* yacc.c:1645 */ break; - case 34: -#line 484 "awkgram.y" /* yacc.c:1645 */ + case 38: +#line 525 "awkgram.y" /* yacc.c:1645 */ { want_regexp = true; } -#line 2234 "awkgram.c" /* yacc.c:1645 */ +#line 2299 "awkgram.c" /* yacc.c:1645 */ break; - case 35: -#line 486 "awkgram.y" /* yacc.c:1645 */ + case 39: +#line 527 "awkgram.y" /* yacc.c:1645 */ { NODE *n, *exp; char *re; @@ -2263,11 +2328,11 @@ yyreduce: (yyval)->opcode = Op_match_rec; (yyval)->memory = n; } -#line 2267 "awkgram.c" /* yacc.c:1645 */ +#line 2332 "awkgram.c" /* yacc.c:1645 */ break; - case 36: -#line 518 "awkgram.y" /* yacc.c:1645 */ + case 40: +#line 559 "awkgram.y" /* yacc.c:1645 */ { char *re; size_t len; @@ -2280,112 +2345,100 @@ yyreduce: (yyval)->opcode = Op_push_re; (yyval)->memory = make_typed_regex(re, len); } -#line 2284 "awkgram.c" /* yacc.c:1645 */ +#line 2349 "awkgram.c" /* yacc.c:1645 */ break; - case 37: -#line 533 "awkgram.y" /* yacc.c:1645 */ + case 41: +#line 574 "awkgram.y" /* yacc.c:1645 */ { bcfree((yyvsp[0])); } -#line 2290 "awkgram.c" /* yacc.c:1645 */ +#line 2355 "awkgram.c" /* yacc.c:1645 */ break; - case 39: -#line 539 "awkgram.y" /* yacc.c:1645 */ - { - if (prior_comment != NULL) { - (yyval) = list_create(prior_comment); - prior_comment = NULL; - } else if (comment != NULL) { - (yyval) = list_create(comment); - comment = NULL; - } else - (yyval) = NULL; - } -#line 2305 "awkgram.c" /* yacc.c:1645 */ + case 43: +#line 580 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 2361 "awkgram.c" /* yacc.c:1645 */ break; - case 40: -#line 550 "awkgram.y" /* yacc.c:1645 */ + case 44: +#line 582 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[0]) == NULL) { - if (prior_comment != NULL) { - (yyval) = list_append((yyvsp[-1]), prior_comment); - prior_comment = NULL; - if (comment != NULL) { - (yyval) = list_append((yyval), comment); - comment = NULL; - } - } else if (comment != NULL) { - (yyval) = list_append((yyvsp[-1]), comment); - comment = NULL; - } else - (yyval) = (yyvsp[-1]); + (yyval) = (yyvsp[-1]); } else { add_lint((yyvsp[0]), LINT_no_effect); if ((yyvsp[-1]) == NULL) { - if (prior_comment != NULL) { - (yyval) = list_append((yyvsp[0]), prior_comment); - prior_comment = NULL; - if (comment != NULL) { - (yyval) = list_append((yyval), comment); - comment = NULL; - } - } else if (comment != NULL) { - (yyval) = list_append((yyvsp[0]), comment); - comment = NULL; - } else - (yyval) = (yyvsp[0]); + (yyval) = (yyvsp[0]); } else { - if (prior_comment != NULL) { - list_append((yyvsp[0]), prior_comment); - prior_comment = NULL; - if (comment != NULL) { - 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])); } } + + if (trailing_comment != NULL) { + (yyval) = list_append((yyval), trailing_comment); + trailing_comment = NULL; + } + yyerrok; } -#line 2356 "awkgram.c" /* yacc.c:1645 */ +#line 2385 "awkgram.c" /* yacc.c:1645 */ break; - case 41: -#line 597 "awkgram.y" /* yacc.c:1645 */ + case 45: +#line 602 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 2362 "awkgram.c" /* yacc.c:1645 */ +#line 2391 "awkgram.c" /* yacc.c:1645 */ break; - case 44: + case 46: +#line 606 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); } +#line 2397 "awkgram.c" /* yacc.c:1645 */ + break; + + case 47: #line 607 "awkgram.y" /* yacc.c:1645 */ - { (yyval) = NULL; } -#line 2368 "awkgram.c" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); } +#line 2403 "awkgram.c" /* yacc.c:1645 */ break; - case 45: -#line 609 "awkgram.y" /* yacc.c:1645 */ - { (yyval) = (yyvsp[-1]); } -#line 2374 "awkgram.c" /* yacc.c:1645 */ + case 48: +#line 612 "awkgram.y" /* yacc.c:1645 */ + { + if ((yyvsp[0]) != NULL) { + INSTRUCTION *ip; + + merge_comments((yyvsp[0]), NULL); + ip = list_create(instruction(Op_no_op)); + (yyval) = list_append(ip, (yyvsp[0])); + } else + (yyval) = NULL; + } +#line 2418 "awkgram.c" /* yacc.c:1645 */ break; - case 46: -#line 611 "awkgram.y" /* yacc.c:1645 */ + case 49: +#line 623 "awkgram.y" /* yacc.c:1645 */ + { + trailing_comment = (yyvsp[0]); // NULL or comment + (yyval) = make_braced_statements((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); + } +#line 2427 "awkgram.c" /* yacc.c:1645 */ + break; + + case 50: +#line 628 "awkgram.y" /* yacc.c:1645 */ { if (do_pretty_print) (yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count)); else (yyval) = (yyvsp[0]); } -#line 2385 "awkgram.c" /* yacc.c:1645 */ +#line 2438 "awkgram.c" /* yacc.c:1645 */ break; - case 47: -#line 618 "awkgram.y" /* yacc.c:1645 */ + case 51: +#line 635 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt; INSTRUCTION *ip, *nextc, *tbreak; @@ -2403,8 +2456,9 @@ yyreduce: if ((yyvsp[-2]) != NULL) { curr = (yyvsp[-2])->nexti; bcfree((yyvsp[-2])); /* Op_list */ - } /* else - curr = NULL; */ + } + /* else + curr = NULL; */ for (; curr != NULL; curr = nextc) { INSTRUCTION *caseexp = curr->case_exp; @@ -2460,26 +2514,43 @@ yyreduce: ip = (yyvsp[-6]); if (do_pretty_print) { + // first merge comments + INSTRUCTION *head_comment = NULL; + + if ((yyvsp[-4]) != NULL && (yyvsp[-3]) != NULL) { + merge_comments((yyvsp[-4]), (yyvsp[-3])); + head_comment = (yyvsp[-4]); + } else if ((yyvsp[-4]) != NULL) + head_comment = (yyvsp[-4]); + else + head_comment = (yyvsp[-3]); + + (yyvsp[-8])->comment = head_comment; + (void) list_prepend(ip, (yyvsp[-8])); (void) list_prepend(ip, instruction(Op_exec_count)); (yyvsp[-8])->target_break = tbreak; ((yyvsp[-8]) + 1)->switch_start = cexp->nexti; ((yyvsp[-8]) + 1)->switch_end = cexp->lasti; - }/* else - $1 is NULL */ + ((yyvsp[-8]) + 1)->switch_end->comment = (yyvsp[0]); + } + /* else + $1 is NULL */ (void) list_append(cexp, dflt); (void) list_merge(ip, cexp); + if ((yyvsp[-1]) != NULL) + (void) list_append(cstmt, (yyvsp[-1])); (yyval) = list_merge(ip, cstmt); break_allowed--; fix_break_continue(ip, tbreak, NULL); } -#line 2479 "awkgram.c" /* yacc.c:1645 */ +#line 2550 "awkgram.c" /* yacc.c:1645 */ break; - case 48: -#line 708 "awkgram.y" /* yacc.c:1645 */ + case 52: +#line 743 "awkgram.y" /* yacc.c:1645 */ { /* * ----------------- @@ -2508,8 +2579,17 @@ yyreduce: (yyvsp[-5])->target_continue = tcont; ((yyvsp[-5]) + 1)->while_body = ip->lasti; (void) list_prepend(ip, (yyvsp[-5])); - }/* else - $1 is NULL */ + } + /* else + $1 is NULL */ + + if ((yyvsp[-1]) != NULL) { + if ((yyvsp[0]) == NULL) + (yyvsp[0]) = list_create(instruction(Op_no_op)); + + (yyvsp[-1])->memory->comment_type = BLOCK_COMMENT; + (yyvsp[0]) = list_prepend((yyvsp[0]), (yyvsp[-1])); + } if ((yyvsp[0]) != NULL) (void) list_merge(ip, (yyvsp[0])); @@ -2521,11 +2601,11 @@ yyreduce: continue_allowed--; fix_break_continue(ip, tbreak, tcont); } -#line 2525 "awkgram.c" /* yacc.c:1645 */ +#line 2605 "awkgram.c" /* yacc.c:1645 */ break; - case 49: -#line 750 "awkgram.y" /* yacc.c:1645 */ + case 53: +#line 794 "awkgram.y" /* yacc.c:1645 */ { /* * ----------------- @@ -2548,8 +2628,13 @@ yyreduce: ip = list_merge((yyvsp[-5]), (yyvsp[-2])); else ip = list_prepend((yyvsp[-2]), instruction(Op_no_op)); + + if ((yyvsp[-6]) != NULL) + (void) list_prepend(ip, (yyvsp[-6])); + if (do_pretty_print) (void) list_prepend(ip, instruction(Op_exec_count)); + (void) list_append(ip, instruction(Op_jmp_true)); ip->lasti->target_jmp = ip->nexti; (yyval) = list_append(ip, tbreak); @@ -2564,14 +2649,17 @@ yyreduce: ((yyvsp[-7]) + 1)->doloop_cond = tcont; (yyval) = list_prepend(ip, (yyvsp[-7])); bcfree((yyvsp[-4])); - } /* else + if ((yyvsp[0]) != NULL) + (yyvsp[-7])->comment = (yyvsp[0]); + } + /* else $1 and $4 are NULLs */ } -#line 2571 "awkgram.c" /* yacc.c:1645 */ +#line 2659 "awkgram.c" /* yacc.c:1645 */ break; - case 50: -#line 792 "awkgram.y" /* yacc.c:1645 */ + case 54: +#line 844 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *ip; char *var_name = (yyvsp[-5])->lextok; @@ -2584,7 +2672,8 @@ yyreduce: && strcmp((yyvsp[0])->nexti->memory->vname, var_name) == 0 ) { - /* Efficiency hack. Recognize the special case of + /* + * Efficiency hack. Recognize the special case of * * for (iggy in foo) * delete foo[iggy] @@ -2616,6 +2705,10 @@ yyreduce: bcfree((yyvsp[-5])); bcfree((yyvsp[-4])); bcfree((yyvsp[-3])); + if ((yyvsp[-1]) != NULL) { + merge_comments((yyvsp[-1]), NULL); + (yyvsp[0]) = list_prepend((yyvsp[0]), (yyvsp[-1])); + } (yyval) = (yyvsp[0]); } else goto regular_loop; @@ -2650,8 +2743,9 @@ regular_loop: (yyvsp[-7])->target_continue = tcont; (yyvsp[-7])->target_break = tbreak; (void) list_append(ip, (yyvsp[-7])); - } /* else - $1 is NULL */ + } + /* else + $1 is NULL */ /* add update_FOO instruction if necessary */ if ((yyvsp[-4])->array_var->type == Node_var && (yyvsp[-4])->array_var->var_update) { @@ -2672,8 +2766,15 @@ regular_loop: ((yyvsp[-7]) + 1)->forloop_body = ip->lasti; } - if ((yyvsp[0]) != NULL) + if ((yyvsp[-1]) != NULL) + merge_comments((yyvsp[-1]), NULL); + + if ((yyvsp[0]) != NULL) { + if ((yyvsp[-1]) != NULL) + (yyvsp[0]) = list_prepend((yyvsp[0]), (yyvsp[-1])); (void) list_merge(ip, (yyvsp[0])); + } else if ((yyvsp[-1]) != NULL) + (void) list_append(ip, (yyvsp[-1])); (void) list_append(ip, instruction(Op_jmp)); ip->lasti->target_jmp = (yyvsp[-4]); @@ -2684,73 +2785,100 @@ regular_loop: break_allowed--; continue_allowed--; } -#line 2688 "awkgram.c" /* yacc.c:1645 */ +#line 2789 "awkgram.c" /* yacc.c:1645 */ break; - case 51: -#line 905 "awkgram.y" /* yacc.c:1645 */ + case 55: +#line 970 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-7]) != NULL) { + merge_comments((yyvsp[-7]), NULL); + (yyvsp[-11])->comment = (yyvsp[-7]); + } + if ((yyvsp[-4]) != NULL) { + merge_comments((yyvsp[-4]), NULL); + if ((yyvsp[-11])->comment == NULL) { + (yyvsp[-4])->memory->comment_type = FOR_COMMENT; + (yyvsp[-11])->comment = (yyvsp[-4]); + } else + (yyvsp[-11])->comment->comment = (yyvsp[-4]); + } + if ((yyvsp[-1]) != NULL) + (yyvsp[0]) = list_prepend((yyvsp[0]), (yyvsp[-1])); (yyval) = mk_for_loop((yyvsp[-11]), (yyvsp[-9]), (yyvsp[-6]), (yyvsp[-3]), (yyvsp[0])); break_allowed--; continue_allowed--; } -#line 2699 "awkgram.c" /* yacc.c:1645 */ +#line 2814 "awkgram.c" /* yacc.c:1645 */ break; - case 52: -#line 912 "awkgram.y" /* yacc.c:1645 */ + case 56: +#line 991 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-6]) != NULL) { + merge_comments((yyvsp[-6]), NULL); + (yyvsp[-10])->comment = (yyvsp[-6]); + } + if ((yyvsp[-4]) != NULL) { + merge_comments((yyvsp[-4]), NULL); + if ((yyvsp[-10])->comment == NULL) { + (yyvsp[-4])->memory->comment_type = FOR_COMMENT; + (yyvsp[-10])->comment = (yyvsp[-4]); + } else + (yyvsp[-10])->comment->comment = (yyvsp[-4]); + } + if ((yyvsp[-1]) != NULL) + (yyvsp[0]) = list_prepend((yyvsp[0]), (yyvsp[-1])); (yyval) = mk_for_loop((yyvsp[-10]), (yyvsp[-8]), (INSTRUCTION *) NULL, (yyvsp[-3]), (yyvsp[0])); break_allowed--; continue_allowed--; } -#line 2710 "awkgram.c" /* yacc.c:1645 */ +#line 2839 "awkgram.c" /* yacc.c:1645 */ break; - case 53: -#line 919 "awkgram.y" /* yacc.c:1645 */ + case 57: +#line 1012 "awkgram.y" /* yacc.c:1645 */ { if (do_pretty_print) (yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count)); else (yyval) = (yyvsp[0]); - (yyval) = add_pending_comment((yyval)); } -#line 2722 "awkgram.c" /* yacc.c:1645 */ +#line 2850 "awkgram.c" /* yacc.c:1645 */ break; - case 54: -#line 930 "awkgram.y" /* yacc.c:1645 */ + case 58: +#line 1022 "awkgram.y" /* yacc.c:1645 */ { if (! break_allowed) error_ln((yyvsp[-1])->source_line, _("`break' is not allowed outside a loop or switch")); (yyvsp[-1])->target_jmp = NULL; (yyval) = list_create((yyvsp[-1])); - (yyval) = add_pending_comment((yyval)); - + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); } -#line 2736 "awkgram.c" /* yacc.c:1645 */ +#line 2864 "awkgram.c" /* yacc.c:1645 */ break; - case 55: -#line 940 "awkgram.y" /* yacc.c:1645 */ + case 59: +#line 1032 "awkgram.y" /* yacc.c:1645 */ { if (! continue_allowed) error_ln((yyvsp[-1])->source_line, _("`continue' is not allowed outside a loop")); (yyvsp[-1])->target_jmp = NULL; (yyval) = list_create((yyvsp[-1])); - (yyval) = add_pending_comment((yyval)); - + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); } -#line 2750 "awkgram.c" /* yacc.c:1645 */ +#line 2878 "awkgram.c" /* yacc.c:1645 */ break; - case 56: -#line 950 "awkgram.y" /* yacc.c:1645 */ + case 60: +#line 1042 "awkgram.y" /* yacc.c:1645 */ { /* if inside function (rule = 0), resolve context at run-time */ if (rule && rule != Rule) @@ -2758,13 +2886,14 @@ regular_loop: _("`next' used in %s action"), ruletab[rule]); (yyvsp[-1])->target_jmp = ip_rec; (yyval) = list_create((yyvsp[-1])); - (yyval) = add_pending_comment((yyval)); + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); } -#line 2764 "awkgram.c" /* yacc.c:1645 */ +#line 2893 "awkgram.c" /* yacc.c:1645 */ break; - case 57: -#line 960 "awkgram.y" /* yacc.c:1645 */ + case 61: +#line 1053 "awkgram.y" /* yacc.c:1645 */ { /* if inside function (rule = 0), resolve context at run-time */ if (rule == BEGIN || rule == END || rule == ENDFILE) @@ -2774,13 +2903,14 @@ regular_loop: (yyvsp[-1])->target_newfile = ip_newfile; (yyvsp[-1])->target_endfile = ip_endfile; (yyval) = list_create((yyvsp[-1])); - (yyval) = add_pending_comment((yyval)); + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); } -#line 2780 "awkgram.c" /* yacc.c:1645 */ +#line 2910 "awkgram.c" /* yacc.c:1645 */ break; - case 58: -#line 972 "awkgram.y" /* yacc.c:1645 */ + case 62: +#line 1066 "awkgram.y" /* yacc.c:1645 */ { /* Initialize the two possible jump targets, the actual target * is resolved at run-time. @@ -2794,22 +2924,23 @@ regular_loop: (yyval)->nexti->memory = dupnode(Nnull_string); } else (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); - (yyval) = add_pending_comment((yyval)); + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); } -#line 2800 "awkgram.c" /* yacc.c:1645 */ +#line 2931 "awkgram.c" /* yacc.c:1645 */ break; - case 59: -#line 988 "awkgram.y" /* yacc.c:1645 */ + case 63: +#line 1083 "awkgram.y" /* yacc.c:1645 */ { if (! in_function) yyerror(_("`return' used outside function context")); } -#line 2809 "awkgram.c" /* yacc.c:1645 */ +#line 2940 "awkgram.c" /* yacc.c:1645 */ break; - case 60: -#line 991 "awkgram.y" /* yacc.c:1645 */ + case 64: +#line 1086 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-1]) == NULL) { (yyval) = list_create((yyvsp[-3])); @@ -2817,20 +2948,31 @@ regular_loop: (yyval)->nexti->memory = dupnode(Nnull_string); } else (yyval) = list_append((yyvsp[-1]), (yyvsp[-3])); + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyval), (yyvsp[0])); + } +#line 2955 "awkgram.c" /* yacc.c:1645 */ + break; - (yyval) = add_pending_comment((yyval)); + case 65: +#line 1097 "awkgram.y" /* yacc.c:1645 */ + { + if ((yyvsp[0]) != NULL) + (yyval) = list_append((yyvsp[-1]), (yyvsp[0])); + else + (yyval) = (yyvsp[-1]); } -#line 2824 "awkgram.c" /* yacc.c:1645 */ +#line 2966 "awkgram.c" /* yacc.c:1645 */ break; - case 62: -#line 1013 "awkgram.y" /* yacc.c:1645 */ + case 66: +#line 1114 "awkgram.y" /* yacc.c:1645 */ { in_print = true; in_parens = 0; } -#line 2830 "awkgram.c" /* yacc.c:1645 */ +#line 2972 "awkgram.c" /* yacc.c:1645 */ break; - case 63: -#line 1014 "awkgram.y" /* yacc.c:1645 */ + case 67: +#line 1115 "awkgram.y" /* yacc.c:1645 */ { /* * Optimization: plain `print' has no expression list, so $3 is null. @@ -2838,7 +2980,7 @@ regular_loop: * which is faster for these two cases. */ - if ((yyvsp[-3])->opcode == Op_K_print && + if (do_optimize && (yyvsp[-3])->opcode == Op_K_print && ((yyvsp[-1]) == NULL || ((yyvsp[-1])->lasti->opcode == Op_field_spec && (yyvsp[-1])->nexti->nexti->nexti == (yyvsp[-1])->lasti @@ -2926,19 +3068,18 @@ regular_print: } } } - (yyval) = add_pending_comment((yyval)); } -#line 2932 "awkgram.c" /* yacc.c:1645 */ +#line 3073 "awkgram.c" /* yacc.c:1645 */ break; - case 64: -#line 1112 "awkgram.y" /* yacc.c:1645 */ + case 68: +#line 1212 "awkgram.y" /* yacc.c:1645 */ { sub_counter = 0; } -#line 2938 "awkgram.c" /* yacc.c:1645 */ +#line 3079 "awkgram.c" /* yacc.c:1645 */ break; - case 65: -#line 1113 "awkgram.y" /* yacc.c:1645 */ + case 69: +#line 1213 "awkgram.y" /* yacc.c:1645 */ { char *arr = (yyvsp[-2])->lextok; @@ -2970,13 +3111,12 @@ regular_print: (yyvsp[-3])->expr_count = sub_counter; (yyval) = list_append(list_append((yyvsp[0]), (yyvsp[-2])), (yyvsp[-3])); } - (yyval) = add_pending_comment((yyval)); } -#line 2976 "awkgram.c" /* yacc.c:1645 */ +#line 3116 "awkgram.c" /* yacc.c:1645 */ break; - case 66: -#line 1151 "awkgram.y" /* yacc.c:1645 */ + case 70: +#line 1250 "awkgram.y" /* yacc.c:1645 */ { static bool warned = false; char *arr = (yyvsp[-1])->lextok; @@ -3001,57 +3141,55 @@ regular_print: else if ((yyvsp[-1])->memory == func_table) fatal(_("`delete' is not allowed with FUNCTAB")); } - (yyval) = add_pending_comment((yyval)); } -#line 3007 "awkgram.c" /* yacc.c:1645 */ +#line 3146 "awkgram.c" /* yacc.c:1645 */ break; - case 67: -#line 1178 "awkgram.y" /* yacc.c:1645 */ + case 71: +#line 1276 "awkgram.y" /* yacc.c:1645 */ { (yyval) = optimize_assignment((yyvsp[0])); - (yyval) = add_pending_comment((yyval)); } -#line 3016 "awkgram.c" /* yacc.c:1645 */ +#line 3154 "awkgram.c" /* yacc.c:1645 */ break; - case 68: -#line 1186 "awkgram.y" /* yacc.c:1645 */ + case 72: +#line 1283 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3022 "awkgram.c" /* yacc.c:1645 */ +#line 3160 "awkgram.c" /* yacc.c:1645 */ break; - case 69: -#line 1188 "awkgram.y" /* yacc.c:1645 */ + case 73: +#line 1285 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3028 "awkgram.c" /* yacc.c:1645 */ +#line 3166 "awkgram.c" /* yacc.c:1645 */ break; - case 70: -#line 1193 "awkgram.y" /* yacc.c:1645 */ + case 74: +#line 1290 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3034 "awkgram.c" /* yacc.c:1645 */ +#line 3172 "awkgram.c" /* yacc.c:1645 */ break; - case 71: -#line 1195 "awkgram.y" /* yacc.c:1645 */ + case 75: +#line 1292 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-1]) == NULL) (yyval) = list_create((yyvsp[0])); else (yyval) = list_prepend((yyvsp[-1]), (yyvsp[0])); } -#line 3045 "awkgram.c" /* yacc.c:1645 */ +#line 3183 "awkgram.c" /* yacc.c:1645 */ break; - case 72: -#line 1202 "awkgram.y" /* yacc.c:1645 */ + case 76: +#line 1299 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3051 "awkgram.c" /* yacc.c:1645 */ +#line 3189 "awkgram.c" /* yacc.c:1645 */ break; - case 73: -#line 1207 "awkgram.y" /* yacc.c:1645 */ + case 77: +#line 1304 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *casestmt = (yyvsp[0]); if ((yyvsp[0]) == NULL) @@ -3060,14 +3198,15 @@ regular_print: (void) list_prepend(casestmt, instruction(Op_exec_count)); (yyvsp[-4])->case_exp = (yyvsp[-3]); (yyvsp[-4])->case_stmt = casestmt; + (yyvsp[-4])->comment = (yyvsp[-1]); bcfree((yyvsp[-2])); (yyval) = (yyvsp[-4]); } -#line 3067 "awkgram.c" /* yacc.c:1645 */ +#line 3206 "awkgram.c" /* yacc.c:1645 */ break; - case 74: -#line 1219 "awkgram.y" /* yacc.c:1645 */ + case 78: +#line 1317 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *casestmt = (yyvsp[0]); if ((yyvsp[0]) == NULL) @@ -3076,19 +3215,20 @@ regular_print: (void) list_prepend(casestmt, instruction(Op_exec_count)); bcfree((yyvsp[-2])); (yyvsp[-3])->case_stmt = casestmt; + (yyvsp[-3])->comment = (yyvsp[-1]); (yyval) = (yyvsp[-3]); } -#line 3082 "awkgram.c" /* yacc.c:1645 */ +#line 3222 "awkgram.c" /* yacc.c:1645 */ break; - case 75: -#line 1233 "awkgram.y" /* yacc.c:1645 */ + case 79: +#line 1332 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3088 "awkgram.c" /* yacc.c:1645 */ +#line 3228 "awkgram.c" /* yacc.c:1645 */ break; - case 76: -#line 1235 "awkgram.y" /* yacc.c:1645 */ + case 80: +#line 1334 "awkgram.y" /* yacc.c:1645 */ { NODE *n = (yyvsp[0])->memory; (void) force_number(n); @@ -3096,28 +3236,28 @@ regular_print: bcfree((yyvsp[-1])); (yyval) = (yyvsp[0]); } -#line 3100 "awkgram.c" /* yacc.c:1645 */ +#line 3240 "awkgram.c" /* yacc.c:1645 */ break; - case 77: -#line 1243 "awkgram.y" /* yacc.c:1645 */ + case 81: +#line 1342 "awkgram.y" /* yacc.c:1645 */ { NODE *n = (yyvsp[0])->lasti->memory; bcfree((yyvsp[-1])); add_sign_to_num(n, '+'); (yyval) = (yyvsp[0]); } -#line 3111 "awkgram.c" /* yacc.c:1645 */ +#line 3251 "awkgram.c" /* yacc.c:1645 */ break; - case 78: -#line 1250 "awkgram.y" /* yacc.c:1645 */ + case 82: +#line 1349 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3117 "awkgram.c" /* yacc.c:1645 */ +#line 3257 "awkgram.c" /* yacc.c:1645 */ break; - case 79: -#line 1252 "awkgram.y" /* yacc.c:1645 */ + case 83: +#line 1351 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[0])->memory->type == Node_regex) (yyvsp[0])->opcode = Op_push_re; @@ -3125,57 +3265,57 @@ regular_print: (yyvsp[0])->opcode = Op_push; (yyval) = (yyvsp[0]); } -#line 3129 "awkgram.c" /* yacc.c:1645 */ +#line 3269 "awkgram.c" /* yacc.c:1645 */ break; - case 80: -#line 1260 "awkgram.y" /* yacc.c:1645 */ + case 84: +#line 1359 "awkgram.y" /* yacc.c:1645 */ { assert(((yyvsp[0])->memory->flags & REGEX) == REGEX); (yyvsp[0])->opcode = Op_push_re; (yyval) = (yyvsp[0]); } -#line 3139 "awkgram.c" /* yacc.c:1645 */ +#line 3279 "awkgram.c" /* yacc.c:1645 */ break; - case 81: -#line 1269 "awkgram.y" /* yacc.c:1645 */ + case 85: +#line 1368 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3145 "awkgram.c" /* yacc.c:1645 */ +#line 3285 "awkgram.c" /* yacc.c:1645 */ break; - case 82: -#line 1271 "awkgram.y" /* yacc.c:1645 */ + case 86: +#line 1370 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3151 "awkgram.c" /* yacc.c:1645 */ +#line 3291 "awkgram.c" /* yacc.c:1645 */ break; - case 84: -#line 1281 "awkgram.y" /* yacc.c:1645 */ + case 88: +#line 1380 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[-1]); } -#line 3159 "awkgram.c" /* yacc.c:1645 */ +#line 3299 "awkgram.c" /* yacc.c:1645 */ break; - case 85: -#line 1288 "awkgram.y" /* yacc.c:1645 */ + case 89: +#line 1387 "awkgram.y" /* yacc.c:1645 */ { in_print = false; in_parens = 0; (yyval) = NULL; } -#line 3169 "awkgram.c" /* yacc.c:1645 */ +#line 3309 "awkgram.c" /* yacc.c:1645 */ break; - case 86: -#line 1293 "awkgram.y" /* yacc.c:1645 */ + case 90: +#line 1392 "awkgram.y" /* yacc.c:1645 */ { in_print = false; in_parens = 0; } -#line 3175 "awkgram.c" /* yacc.c:1645 */ +#line 3315 "awkgram.c" /* yacc.c:1645 */ break; - case 87: -#line 1294 "awkgram.y" /* yacc.c:1645 */ + case 91: +#line 1393 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-2])->redir_type == redirect_twoway && (yyvsp[0])->lasti->opcode == Op_K_getline_redir @@ -3185,139 +3325,197 @@ regular_print: lintwarn(_("concatenation as I/O `>' redirection target is ambiguous")); (yyval) = list_prepend((yyvsp[0]), (yyvsp[-2])); } -#line 3189 "awkgram.c" /* yacc.c:1645 */ +#line 3329 "awkgram.c" /* yacc.c:1645 */ break; - case 88: -#line 1307 "awkgram.y" /* yacc.c:1645 */ + case 92: +#line 1406 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-1]) != NULL) + (yyvsp[-5])->comment = (yyvsp[-1]); (yyval) = mk_condition((yyvsp[-3]), (yyvsp[-5]), (yyvsp[0]), NULL, NULL); } -#line 3197 "awkgram.c" /* yacc.c:1645 */ +#line 3339 "awkgram.c" /* yacc.c:1645 */ break; - case 89: -#line 1312 "awkgram.y" /* yacc.c:1645 */ + case 93: +#line 1413 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-4]) != NULL) + (yyvsp[-8])->comment = (yyvsp[-4]); + if ((yyvsp[-1]) != NULL) + (yyvsp[-2])->comment = (yyvsp[-1]); (yyval) = mk_condition((yyvsp[-6]), (yyvsp[-8]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[0])); } -#line 3205 "awkgram.c" /* yacc.c:1645 */ +#line 3351 "awkgram.c" /* yacc.c:1645 */ break; case 94: -#line 1329 "awkgram.y" /* yacc.c:1645 */ - { (yyval) = NULL; } -#line 3211 "awkgram.c" /* yacc.c:1645 */ +#line 1424 "awkgram.y" /* yacc.c:1645 */ + { + (yyval) = (yyvsp[0]); + } +#line 3359 "awkgram.c" /* yacc.c:1645 */ break; case 95: -#line 1331 "awkgram.y" /* yacc.c:1645 */ +#line 1428 "awkgram.y" /* yacc.c:1645 */ { - bcfree((yyvsp[-1])); - (yyval) = (yyvsp[0]); + if ((yyvsp[-1]) != NULL && (yyvsp[0]) != NULL) { + if ((yyvsp[-1])->memory->comment_type == EOL_COMMENT) { + assert((yyvsp[0])->memory->comment_type == BLOCK_COMMENT); + (yyvsp[-1])->comment = (yyvsp[0]); // chain them + } else { + merge_comments((yyvsp[-1]), (yyvsp[0])); + } + + (yyval) = (yyvsp[-1]); + } else if ((yyvsp[-1]) != NULL) { + (yyval) = (yyvsp[-1]); + } else if ((yyvsp[0]) != NULL) { + (yyval) = (yyvsp[0]); + } else + (yyval) = NULL; } -#line 3220 "awkgram.c" /* yacc.c:1645 */ +#line 3381 "awkgram.c" /* yacc.c:1645 */ break; case 96: -#line 1339 "awkgram.y" /* yacc.c:1645 */ +#line 1449 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3226 "awkgram.c" /* yacc.c:1645 */ +#line 3387 "awkgram.c" /* yacc.c:1645 */ break; case 97: -#line 1341 "awkgram.y" /* yacc.c:1645 */ +#line 1451 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3232 "awkgram.c" /* yacc.c:1645 */ +#line 3393 "awkgram.c" /* yacc.c:1645 */ break; case 98: -#line 1346 "awkgram.y" /* yacc.c:1645 */ +#line 1456 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 3399 "awkgram.c" /* yacc.c:1645 */ + break; + + case 99: +#line 1458 "awkgram.y" /* yacc.c:1645 */ + { + bcfree((yyvsp[-1])); + (yyval) = (yyvsp[0]); + } +#line 3408 "awkgram.c" /* yacc.c:1645 */ + break; + + case 100: +#line 1466 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 3414 "awkgram.c" /* yacc.c:1645 */ + break; + + case 101: +#line 1468 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); } +#line 3420 "awkgram.c" /* yacc.c:1645 */ + break; + + case 102: +#line 1473 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->param_count = 0; (yyval) = list_create((yyvsp[0])); } -#line 3241 "awkgram.c" /* yacc.c:1645 */ +#line 3429 "awkgram.c" /* yacc.c:1645 */ break; - case 99: -#line 1351 "awkgram.y" /* yacc.c:1645 */ + case 103: +#line 1478 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-2]) != NULL && (yyvsp[0]) != NULL) { - (yyvsp[0])->param_count = (yyvsp[-2])->lasti->param_count + 1; + (yyvsp[0])->param_count = (yyvsp[-2])->lasti->param_count + 1; (yyval) = list_append((yyvsp[-2]), (yyvsp[0])); yyerrok; + + // newlines are allowed after commas, catch any comments + if ((yyvsp[-1]) != NULL) { + if ((yyvsp[-2])->comment != NULL) + merge_comments((yyvsp[-2])->comment, (yyvsp[-1])); + else + (yyvsp[-2])->comment = (yyvsp[-1]); + } } else (yyval) = NULL; } -#line 3254 "awkgram.c" /* yacc.c:1645 */ +#line 3450 "awkgram.c" /* yacc.c:1645 */ break; - case 100: -#line 1360 "awkgram.y" /* yacc.c:1645 */ + case 104: +#line 1495 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3260 "awkgram.c" /* yacc.c:1645 */ +#line 3456 "awkgram.c" /* yacc.c:1645 */ break; - case 101: -#line 1362 "awkgram.y" /* yacc.c:1645 */ + case 105: +#line 1497 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[-1]); } -#line 3266 "awkgram.c" /* yacc.c:1645 */ +#line 3462 "awkgram.c" /* yacc.c:1645 */ break; - case 102: -#line 1364 "awkgram.y" /* yacc.c:1645 */ + case 106: +#line 1499 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[-2]); } -#line 3272 "awkgram.c" /* yacc.c:1645 */ +#line 3468 "awkgram.c" /* yacc.c:1645 */ break; - case 103: -#line 1370 "awkgram.y" /* yacc.c:1645 */ + case 107: +#line 1505 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3278 "awkgram.c" /* yacc.c:1645 */ +#line 3474 "awkgram.c" /* yacc.c:1645 */ break; - case 104: -#line 1372 "awkgram.y" /* yacc.c:1645 */ + case 108: +#line 1507 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3284 "awkgram.c" /* yacc.c:1645 */ +#line 3480 "awkgram.c" /* yacc.c:1645 */ break; - case 105: -#line 1377 "awkgram.y" /* yacc.c:1645 */ + case 109: +#line 1512 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3290 "awkgram.c" /* yacc.c:1645 */ +#line 3486 "awkgram.c" /* yacc.c:1645 */ break; - case 106: -#line 1379 "awkgram.y" /* yacc.c:1645 */ + case 110: +#line 1514 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3296 "awkgram.c" /* yacc.c:1645 */ +#line 3492 "awkgram.c" /* yacc.c:1645 */ break; - case 107: -#line 1384 "awkgram.y" /* yacc.c:1645 */ + case 111: +#line 1519 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_expression_list(NULL, (yyvsp[0])); } -#line 3302 "awkgram.c" /* yacc.c:1645 */ +#line 3498 "awkgram.c" /* yacc.c:1645 */ break; - case 108: -#line 1386 "awkgram.y" /* yacc.c:1645 */ + case 112: +#line 1521 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-1]) != NULL) + (yyvsp[-2])->lasti->comment = (yyvsp[-1]); (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); yyerrok; } -#line 3311 "awkgram.c" /* yacc.c:1645 */ +#line 3509 "awkgram.c" /* yacc.c:1645 */ break; - case 109: -#line 1391 "awkgram.y" /* yacc.c:1645 */ + case 113: +#line 1528 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3317 "awkgram.c" /* yacc.c:1645 */ +#line 3515 "awkgram.c" /* yacc.c:1645 */ break; - case 110: -#line 1393 "awkgram.y" /* yacc.c:1645 */ + case 114: +#line 1530 "awkgram.y" /* yacc.c:1645 */ { /* * Returning the expression list instead of NULL lets @@ -3325,62 +3523,66 @@ regular_print: */ (yyval) = (yyvsp[-1]); } -#line 3329 "awkgram.c" /* yacc.c:1645 */ +#line 3527 "awkgram.c" /* yacc.c:1645 */ break; - case 111: -#line 1401 "awkgram.y" /* yacc.c:1645 */ + case 115: +#line 1538 "awkgram.y" /* yacc.c:1645 */ { /* Ditto */ (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); } -#line 3338 "awkgram.c" /* yacc.c:1645 */ +#line 3536 "awkgram.c" /* yacc.c:1645 */ break; - case 112: -#line 1406 "awkgram.y" /* yacc.c:1645 */ + case 116: +#line 1543 "awkgram.y" /* yacc.c:1645 */ { /* Ditto */ + if ((yyvsp[-1]) != NULL) + (yyvsp[-2])->lasti->comment = (yyvsp[-1]); (yyval) = (yyvsp[-2]); } -#line 3347 "awkgram.c" /* yacc.c:1645 */ +#line 3547 "awkgram.c" /* yacc.c:1645 */ break; - case 113: -#line 1414 "awkgram.y" /* yacc.c:1645 */ + case 117: +#line 1553 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3353 "awkgram.c" /* yacc.c:1645 */ +#line 3553 "awkgram.c" /* yacc.c:1645 */ break; - case 114: -#line 1416 "awkgram.y" /* yacc.c:1645 */ + case 118: +#line 1555 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3359 "awkgram.c" /* yacc.c:1645 */ +#line 3559 "awkgram.c" /* yacc.c:1645 */ break; - case 115: -#line 1421 "awkgram.y" /* yacc.c:1645 */ + case 119: +#line 1560 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_expression_list(NULL, (yyvsp[0])); } -#line 3365 "awkgram.c" /* yacc.c:1645 */ +#line 3565 "awkgram.c" /* yacc.c:1645 */ break; - case 116: -#line 1423 "awkgram.y" /* yacc.c:1645 */ + case 120: +#line 1562 "awkgram.y" /* yacc.c:1645 */ { + if ((yyvsp[-1]) != NULL) + (yyvsp[-2])->lasti->comment = (yyvsp[-1]); (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); yyerrok; } -#line 3374 "awkgram.c" /* yacc.c:1645 */ +#line 3576 "awkgram.c" /* yacc.c:1645 */ break; - case 117: -#line 1428 "awkgram.y" /* yacc.c:1645 */ + case 121: +#line 1569 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 3380 "awkgram.c" /* yacc.c:1645 */ +#line 3582 "awkgram.c" /* yacc.c:1645 */ break; - case 118: -#line 1430 "awkgram.y" /* yacc.c:1645 */ + case 122: +#line 1571 "awkgram.y" /* yacc.c:1645 */ { /* * Returning the expression list instead of NULL lets @@ -3388,72 +3590,74 @@ regular_print: */ (yyval) = (yyvsp[-1]); } -#line 3392 "awkgram.c" /* yacc.c:1645 */ +#line 3594 "awkgram.c" /* yacc.c:1645 */ break; - case 119: -#line 1438 "awkgram.y" /* yacc.c:1645 */ + case 123: +#line 1579 "awkgram.y" /* yacc.c:1645 */ { /* Ditto */ (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); } -#line 3401 "awkgram.c" /* yacc.c:1645 */ +#line 3603 "awkgram.c" /* yacc.c:1645 */ break; - case 120: -#line 1443 "awkgram.y" /* yacc.c:1645 */ + case 124: +#line 1584 "awkgram.y" /* yacc.c:1645 */ { /* Ditto */ + if ((yyvsp[-1]) != NULL) + (yyvsp[-2])->comment = (yyvsp[-1]); (yyval) = (yyvsp[-2]); } -#line 3410 "awkgram.c" /* yacc.c:1645 */ +#line 3614 "awkgram.c" /* yacc.c:1645 */ break; - case 121: -#line 1450 "awkgram.y" /* yacc.c:1645 */ + case 125: +#line 1593 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3416 "awkgram.c" /* yacc.c:1645 */ +#line 3620 "awkgram.c" /* yacc.c:1645 */ break; - case 122: -#line 1451 "awkgram.y" /* yacc.c:1645 */ + case 126: +#line 1594 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_create((yyvsp[0])); } -#line 3422 "awkgram.c" /* yacc.c:1645 */ +#line 3626 "awkgram.c" /* yacc.c:1645 */ break; - case 123: -#line 1457 "awkgram.y" /* yacc.c:1645 */ + case 127: +#line 1600 "awkgram.y" /* yacc.c:1645 */ { 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 3433 "awkgram.c" /* yacc.c:1645 */ +#line 3637 "awkgram.c" /* yacc.c:1645 */ break; - case 124: -#line 1464 "awkgram.y" /* yacc.c:1645 */ + case 128: +#line 1607 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_assignment((yyvsp[-2]), list_create((yyvsp[0])), (yyvsp[-1])); } -#line 3441 "awkgram.c" /* yacc.c:1645 */ +#line 3645 "awkgram.c" /* yacc.c:1645 */ break; - case 125: -#line 1468 "awkgram.y" /* yacc.c:1645 */ + case 129: +#line 1611 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3447 "awkgram.c" /* yacc.c:1645 */ +#line 3651 "awkgram.c" /* yacc.c:1645 */ break; - case 126: -#line 1470 "awkgram.y" /* yacc.c:1645 */ + case 130: +#line 1613 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3453 "awkgram.c" /* yacc.c:1645 */ +#line 3657 "awkgram.c" /* yacc.c:1645 */ break; - case 127: -#line 1472 "awkgram.y" /* yacc.c:1645 */ + case 131: +#line 1615 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-2])->lasti->opcode == Op_match_rec) warning_ln((yyvsp[-1])->source_line, @@ -3466,11 +3670,11 @@ regular_print: bcfree((yyvsp[0])); (yyval) = list_append((yyvsp[-2]), (yyvsp[-1])); } -#line 3470 "awkgram.c" /* yacc.c:1645 */ +#line 3674 "awkgram.c" /* yacc.c:1645 */ break; - case 128: -#line 1485 "awkgram.y" /* yacc.c:1645 */ + case 132: +#line 1628 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[-2])->lasti->opcode == Op_match_rec) warning_ln((yyvsp[-1])->source_line, @@ -3487,11 +3691,11 @@ regular_print: (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); } } -#line 3491 "awkgram.c" /* yacc.c:1645 */ +#line 3695 "awkgram.c" /* yacc.c:1645 */ break; - case 129: -#line 1502 "awkgram.y" /* yacc.c:1645 */ + case 133: +#line 1645 "awkgram.y" /* yacc.c:1645 */ { if (do_lint_old) warning_ln((yyvsp[-1])->source_line, @@ -3501,91 +3705,91 @@ regular_print: (yyvsp[-1])->expr_count = 1; (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); } -#line 3505 "awkgram.c" /* yacc.c:1645 */ +#line 3709 "awkgram.c" /* yacc.c:1645 */ break; - case 130: -#line 1512 "awkgram.y" /* yacc.c:1645 */ + case 134: +#line 1655 "awkgram.y" /* yacc.c:1645 */ { 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 3516 "awkgram.c" /* yacc.c:1645 */ +#line 3720 "awkgram.c" /* yacc.c:1645 */ break; - case 131: -#line 1519 "awkgram.y" /* yacc.c:1645 */ + case 135: +#line 1662 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_condition((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); } -#line 3522 "awkgram.c" /* yacc.c:1645 */ +#line 3726 "awkgram.c" /* yacc.c:1645 */ break; - case 132: -#line 1521 "awkgram.y" /* yacc.c:1645 */ + case 136: +#line 1664 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3528 "awkgram.c" /* yacc.c:1645 */ +#line 3732 "awkgram.c" /* yacc.c:1645 */ break; - case 133: -#line 1526 "awkgram.y" /* yacc.c:1645 */ + case 137: +#line 1669 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3534 "awkgram.c" /* yacc.c:1645 */ +#line 3738 "awkgram.c" /* yacc.c:1645 */ break; - case 134: -#line 1528 "awkgram.y" /* yacc.c:1645 */ + case 138: +#line 1671 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3540 "awkgram.c" /* yacc.c:1645 */ +#line 3744 "awkgram.c" /* yacc.c:1645 */ break; - case 135: -#line 1530 "awkgram.y" /* yacc.c:1645 */ + case 139: +#line 1673 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->opcode = Op_assign_quotient; (yyval) = (yyvsp[0]); } -#line 3549 "awkgram.c" /* yacc.c:1645 */ +#line 3753 "awkgram.c" /* yacc.c:1645 */ break; - case 136: -#line 1538 "awkgram.y" /* yacc.c:1645 */ + case 140: +#line 1681 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3555 "awkgram.c" /* yacc.c:1645 */ +#line 3759 "awkgram.c" /* yacc.c:1645 */ break; - case 137: -#line 1540 "awkgram.y" /* yacc.c:1645 */ + case 141: +#line 1683 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3561 "awkgram.c" /* yacc.c:1645 */ +#line 3765 "awkgram.c" /* yacc.c:1645 */ break; - case 138: -#line 1545 "awkgram.y" /* yacc.c:1645 */ + case 142: +#line 1688 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3567 "awkgram.c" /* yacc.c:1645 */ +#line 3771 "awkgram.c" /* yacc.c:1645 */ break; - case 139: -#line 1547 "awkgram.y" /* yacc.c:1645 */ + case 143: +#line 1690 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3573 "awkgram.c" /* yacc.c:1645 */ +#line 3777 "awkgram.c" /* yacc.c:1645 */ break; - case 140: -#line 1552 "awkgram.y" /* yacc.c:1645 */ + case 144: +#line 1695 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3579 "awkgram.c" /* yacc.c:1645 */ +#line 3783 "awkgram.c" /* yacc.c:1645 */ break; - case 141: -#line 1554 "awkgram.y" /* yacc.c:1645 */ + case 145: +#line 1697 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 3585 "awkgram.c" /* yacc.c:1645 */ +#line 3789 "awkgram.c" /* yacc.c:1645 */ break; - case 142: -#line 1556 "awkgram.y" /* yacc.c:1645 */ + case 146: +#line 1699 "awkgram.y" /* yacc.c:1645 */ { int count = 2; bool is_simple_var = false; @@ -3639,47 +3843,47 @@ regular_print: max_args = count; } } -#line 3643 "awkgram.c" /* yacc.c:1645 */ +#line 3847 "awkgram.c" /* yacc.c:1645 */ break; - case 144: -#line 1615 "awkgram.y" /* yacc.c:1645 */ + case 148: +#line 1758 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3649 "awkgram.c" /* yacc.c:1645 */ +#line 3853 "awkgram.c" /* yacc.c:1645 */ break; - case 145: -#line 1617 "awkgram.y" /* yacc.c:1645 */ + case 149: +#line 1760 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3655 "awkgram.c" /* yacc.c:1645 */ +#line 3859 "awkgram.c" /* yacc.c:1645 */ break; - case 146: -#line 1619 "awkgram.y" /* yacc.c:1645 */ + case 150: +#line 1762 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3661 "awkgram.c" /* yacc.c:1645 */ +#line 3865 "awkgram.c" /* yacc.c:1645 */ break; - case 147: -#line 1621 "awkgram.y" /* yacc.c:1645 */ + case 151: +#line 1764 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3667 "awkgram.c" /* yacc.c:1645 */ +#line 3871 "awkgram.c" /* yacc.c:1645 */ break; - case 148: -#line 1623 "awkgram.y" /* yacc.c:1645 */ + case 152: +#line 1766 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3673 "awkgram.c" /* yacc.c:1645 */ +#line 3877 "awkgram.c" /* yacc.c:1645 */ break; - case 149: -#line 1625 "awkgram.y" /* yacc.c:1645 */ + case 153: +#line 1768 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3679 "awkgram.c" /* yacc.c:1645 */ +#line 3883 "awkgram.c" /* yacc.c:1645 */ break; - case 150: -#line 1627 "awkgram.y" /* yacc.c:1645 */ + case 154: +#line 1770 "awkgram.y" /* yacc.c:1645 */ { /* * In BEGINFILE/ENDFILE, allow `getline [var] < file' @@ -3693,29 +3897,29 @@ regular_print: _("non-redirected `getline' undefined inside END action")); (yyval) = mk_getline((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), redirect_input); } -#line 3697 "awkgram.c" /* yacc.c:1645 */ +#line 3901 "awkgram.c" /* yacc.c:1645 */ break; - case 151: -#line 1641 "awkgram.y" /* yacc.c:1645 */ + case 155: +#line 1784 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->opcode = Op_postincrement; (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 3706 "awkgram.c" /* yacc.c:1645 */ +#line 3910 "awkgram.c" /* yacc.c:1645 */ break; - case 152: -#line 1646 "awkgram.y" /* yacc.c:1645 */ + case 156: +#line 1789 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->opcode = Op_postdecrement; (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 3715 "awkgram.c" /* yacc.c:1645 */ +#line 3919 "awkgram.c" /* yacc.c:1645 */ break; - case 153: -#line 1651 "awkgram.y" /* yacc.c:1645 */ + case 157: +#line 1794 "awkgram.y" /* yacc.c:1645 */ { if (do_lint_old) { warning_ln((yyvsp[-1])->source_line, @@ -3735,64 +3939,64 @@ regular_print: (yyval) = list_append(list_merge(t, (yyvsp[0])), (yyvsp[-1])); } } -#line 3739 "awkgram.c" /* yacc.c:1645 */ +#line 3943 "awkgram.c" /* yacc.c:1645 */ break; - case 154: -#line 1676 "awkgram.y" /* yacc.c:1645 */ + case 158: +#line 1819 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_getline((yyvsp[-1]), (yyvsp[0]), (yyvsp[-3]), (yyvsp[-2])->redir_type); bcfree((yyvsp[-2])); } -#line 3748 "awkgram.c" /* yacc.c:1645 */ +#line 3952 "awkgram.c" /* yacc.c:1645 */ break; - case 155: -#line 1682 "awkgram.y" /* yacc.c:1645 */ + case 159: +#line 1825 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3754 "awkgram.c" /* yacc.c:1645 */ +#line 3958 "awkgram.c" /* yacc.c:1645 */ break; - case 156: -#line 1684 "awkgram.y" /* yacc.c:1645 */ + case 160: +#line 1827 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3760 "awkgram.c" /* yacc.c:1645 */ +#line 3964 "awkgram.c" /* yacc.c:1645 */ break; - case 157: -#line 1686 "awkgram.y" /* yacc.c:1645 */ + case 161: +#line 1829 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3766 "awkgram.c" /* yacc.c:1645 */ +#line 3970 "awkgram.c" /* yacc.c:1645 */ break; - case 158: -#line 1688 "awkgram.y" /* yacc.c:1645 */ + case 162: +#line 1831 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3772 "awkgram.c" /* yacc.c:1645 */ +#line 3976 "awkgram.c" /* yacc.c:1645 */ break; - case 159: -#line 1690 "awkgram.y" /* yacc.c:1645 */ + case 163: +#line 1833 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3778 "awkgram.c" /* yacc.c:1645 */ +#line 3982 "awkgram.c" /* yacc.c:1645 */ break; - case 160: -#line 1692 "awkgram.y" /* yacc.c:1645 */ + case 164: +#line 1835 "awkgram.y" /* yacc.c:1645 */ { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } -#line 3784 "awkgram.c" /* yacc.c:1645 */ +#line 3988 "awkgram.c" /* yacc.c:1645 */ break; - case 161: -#line 1697 "awkgram.y" /* yacc.c:1645 */ + case 165: +#line 1840 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_create((yyvsp[0])); } -#line 3792 "awkgram.c" /* yacc.c:1645 */ +#line 3996 "awkgram.c" /* yacc.c:1645 */ break; - case 162: -#line 1701 "awkgram.y" /* yacc.c:1645 */ + case 166: +#line 1844 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[0])->opcode == Op_match_rec) { (yyvsp[0])->opcode = Op_nomatch; @@ -3824,11 +4028,11 @@ regular_print: } } } -#line 3828 "awkgram.c" /* yacc.c:1645 */ +#line 4032 "awkgram.c" /* yacc.c:1645 */ break; - case 163: -#line 1733 "awkgram.y" /* yacc.c:1645 */ + case 167: +#line 1876 "awkgram.y" /* yacc.c:1645 */ { // Always include. Allows us to lint warn on // print "foo" > "bar" 1 @@ -3836,31 +4040,31 @@ regular_print: // print "foo" > ("bar" 1) (yyval) = list_append((yyvsp[-1]), bcalloc(Op_parens, 1, sourceline)); } -#line 3840 "awkgram.c" /* yacc.c:1645 */ +#line 4044 "awkgram.c" /* yacc.c:1645 */ break; - case 164: -#line 1741 "awkgram.y" /* yacc.c:1645 */ + case 168: +#line 1884 "awkgram.y" /* yacc.c:1645 */ { (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); if ((yyval) == NULL) YYABORT; } -#line 3850 "awkgram.c" /* yacc.c:1645 */ +#line 4054 "awkgram.c" /* yacc.c:1645 */ break; - case 165: -#line 1747 "awkgram.y" /* yacc.c:1645 */ + case 169: +#line 1890 "awkgram.y" /* yacc.c:1645 */ { (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); if ((yyval) == NULL) YYABORT; } -#line 3860 "awkgram.c" /* yacc.c:1645 */ +#line 4064 "awkgram.c" /* yacc.c:1645 */ break; - case 166: -#line 1753 "awkgram.y" /* yacc.c:1645 */ + case 170: +#line 1896 "awkgram.y" /* yacc.c:1645 */ { static bool warned = false; @@ -3873,45 +4077,45 @@ regular_print: if ((yyval) == NULL) YYABORT; } -#line 3877 "awkgram.c" /* yacc.c:1645 */ +#line 4081 "awkgram.c" /* yacc.c:1645 */ break; - case 169: -#line 1768 "awkgram.y" /* yacc.c:1645 */ + case 173: +#line 1911 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[-1])->opcode = Op_preincrement; (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); } -#line 3886 "awkgram.c" /* yacc.c:1645 */ +#line 4090 "awkgram.c" /* yacc.c:1645 */ break; - case 170: -#line 1773 "awkgram.y" /* yacc.c:1645 */ + case 174: +#line 1916 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[-1])->opcode = Op_predecrement; (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); } -#line 3895 "awkgram.c" /* yacc.c:1645 */ +#line 4099 "awkgram.c" /* yacc.c:1645 */ break; - case 171: -#line 1778 "awkgram.y" /* yacc.c:1645 */ + case 175: +#line 1921 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_create((yyvsp[0])); } -#line 3903 "awkgram.c" /* yacc.c:1645 */ +#line 4107 "awkgram.c" /* yacc.c:1645 */ break; - case 172: -#line 1782 "awkgram.y" /* yacc.c:1645 */ + case 176: +#line 1925 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_create((yyvsp[0])); } -#line 3911 "awkgram.c" /* yacc.c:1645 */ +#line 4115 "awkgram.c" /* yacc.c:1645 */ break; - case 173: -#line 1786 "awkgram.y" /* yacc.c:1645 */ + case 177: +#line 1929 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[0])->lasti->opcode == Op_push_i && ((yyvsp[0])->lasti->memory->flags & STRING) == 0 @@ -3926,11 +4130,11 @@ regular_print: (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); } } -#line 3930 "awkgram.c" /* yacc.c:1645 */ +#line 4134 "awkgram.c" /* yacc.c:1645 */ break; - case 174: -#line 1801 "awkgram.y" /* yacc.c:1645 */ + case 178: +#line 1944 "awkgram.y" /* yacc.c:1645 */ { if ((yyvsp[0])->lasti->opcode == Op_push_i && ((yyvsp[0])->lasti->memory->flags & STRING) == 0 @@ -3948,20 +4152,20 @@ regular_print: (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); } } -#line 3952 "awkgram.c" /* yacc.c:1645 */ +#line 4156 "awkgram.c" /* yacc.c:1645 */ break; - case 175: -#line 1822 "awkgram.y" /* yacc.c:1645 */ + case 179: +#line 1965 "awkgram.y" /* yacc.c:1645 */ { func_use((yyvsp[0])->lasti->func_name, FUNC_USE); (yyval) = (yyvsp[0]); } -#line 3961 "awkgram.c" /* yacc.c:1645 */ +#line 4165 "awkgram.c" /* yacc.c:1645 */ break; - case 176: -#line 1827 "awkgram.y" /* yacc.c:1645 */ + case 180: +#line 1970 "awkgram.y" /* yacc.c:1645 */ { /* indirect function call */ INSTRUCTION *f, *t; @@ -3995,16 +4199,28 @@ regular_print: (yyval) = list_prepend((yyvsp[0]), t); at_seen = false; } -#line 3999 "awkgram.c" /* yacc.c:1645 */ +#line 4203 "awkgram.c" /* yacc.c:1645 */ break; - case 177: -#line 1864 "awkgram.y" /* yacc.c:1645 */ + case 181: +#line 2007 "awkgram.y" /* yacc.c:1645 */ { NODE *n; + const char *name = (yyvsp[-3])->func_name; + + if (current_namespace != awk_namespace && strchr(name, ':') == NULL) { + size_t len = strlen(current_namespace) + 2 + strlen(name) + 1; + char *buf; + + emalloc(buf, char *, len, "direct_func_call"); + sprintf(buf, "%s::%s", current_namespace, name); + + efree((void *) (yyvsp[-3])->func_name); + (yyvsp[-3])->func_name = buf; + } if (! at_seen) { - n = lookup((yyvsp[-3])->func_name); + n = lookup((yyvsp[-3])->func_name, true); if (n != NULL && n->type != Node_func && n->type != Node_ext_func) { error_ln((yyvsp[-3])->source_line, @@ -4012,6 +4228,7 @@ regular_print: (yyvsp[-3])->func_name); } } + param_sanity((yyvsp[-1])); (yyvsp[-3])->opcode = Op_func_call; (yyvsp[-3])->func_body = NULL; @@ -4024,49 +4241,49 @@ regular_print: (yyval) = list_append(t, (yyvsp[-3])); } } -#line 4028 "awkgram.c" /* yacc.c:1645 */ +#line 4245 "awkgram.c" /* yacc.c:1645 */ break; - case 178: -#line 1892 "awkgram.y" /* yacc.c:1645 */ + case 182: +#line 2048 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 4034 "awkgram.c" /* yacc.c:1645 */ +#line 4251 "awkgram.c" /* yacc.c:1645 */ break; - case 179: -#line 1894 "awkgram.y" /* yacc.c:1645 */ + case 183: +#line 2050 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 4040 "awkgram.c" /* yacc.c:1645 */ +#line 4257 "awkgram.c" /* yacc.c:1645 */ break; - case 180: -#line 1899 "awkgram.y" /* yacc.c:1645 */ + case 184: +#line 2055 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 4046 "awkgram.c" /* yacc.c:1645 */ +#line 4263 "awkgram.c" /* yacc.c:1645 */ break; - case 181: -#line 1901 "awkgram.y" /* yacc.c:1645 */ + case 185: +#line 2057 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[-1]); } -#line 4052 "awkgram.c" /* yacc.c:1645 */ +#line 4269 "awkgram.c" /* yacc.c:1645 */ break; - case 182: -#line 1906 "awkgram.y" /* yacc.c:1645 */ + case 186: +#line 2062 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 4058 "awkgram.c" /* yacc.c:1645 */ +#line 4275 "awkgram.c" /* yacc.c:1645 */ break; - case 183: -#line 1908 "awkgram.y" /* yacc.c:1645 */ + case 187: +#line 2064 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); } -#line 4066 "awkgram.c" /* yacc.c:1645 */ +#line 4283 "awkgram.c" /* yacc.c:1645 */ break; - case 184: -#line 1915 "awkgram.y" /* yacc.c:1645 */ + case 188: +#line 2071 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *ip = (yyvsp[0])->lasti; int count = ip->sub_count; /* # of SUBSEP-seperated expressions */ @@ -4080,11 +4297,11 @@ regular_print: sub_counter++; /* count # of dimensions */ (yyval) = (yyvsp[0]); } -#line 4084 "awkgram.c" /* yacc.c:1645 */ +#line 4301 "awkgram.c" /* yacc.c:1645 */ break; - case 185: -#line 1932 "awkgram.y" /* yacc.c:1645 */ + case 189: +#line 2088 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *t = (yyvsp[-1]); if ((yyvsp[-1]) == NULL) { @@ -4098,31 +4315,31 @@ regular_print: (yyvsp[0])->sub_count = count_expressions(&t, false); (yyval) = list_append(t, (yyvsp[0])); } -#line 4102 "awkgram.c" /* yacc.c:1645 */ +#line 4319 "awkgram.c" /* yacc.c:1645 */ break; - case 186: -#line 1949 "awkgram.y" /* yacc.c:1645 */ + case 190: +#line 2105 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); } -#line 4108 "awkgram.c" /* yacc.c:1645 */ +#line 4325 "awkgram.c" /* yacc.c:1645 */ break; - case 187: -#line 1951 "awkgram.y" /* yacc.c:1645 */ + case 191: +#line 2107 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); } -#line 4116 "awkgram.c" /* yacc.c:1645 */ +#line 4333 "awkgram.c" /* yacc.c:1645 */ break; - case 188: -#line 1958 "awkgram.y" /* yacc.c:1645 */ + case 192: +#line 2114 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[-1]); } -#line 4122 "awkgram.c" /* yacc.c:1645 */ +#line 4339 "awkgram.c" /* yacc.c:1645 */ break; - case 189: -#line 1963 "awkgram.y" /* yacc.c:1645 */ + case 193: +#line 2119 "awkgram.y" /* yacc.c:1645 */ { char *var_name = (yyvsp[0])->lextok; @@ -4130,22 +4347,22 @@ regular_print: (yyvsp[0])->memory = variable((yyvsp[0])->source_line, var_name, Node_var_new); (yyval) = list_create((yyvsp[0])); } -#line 4134 "awkgram.c" /* yacc.c:1645 */ +#line 4351 "awkgram.c" /* yacc.c:1645 */ break; - case 190: -#line 1971 "awkgram.y" /* yacc.c:1645 */ + case 194: +#line 2127 "awkgram.y" /* yacc.c:1645 */ { 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 4145 "awkgram.c" /* yacc.c:1645 */ +#line 4362 "awkgram.c" /* yacc.c:1645 */ break; - case 191: -#line 1981 "awkgram.y" /* yacc.c:1645 */ + case 195: +#line 2137 "awkgram.y" /* yacc.c:1645 */ { INSTRUCTION *ip = (yyvsp[0])->nexti; if (ip->opcode == Op_push @@ -4157,73 +4374,85 @@ regular_print: } else (yyval) = (yyvsp[0]); } -#line 4161 "awkgram.c" /* yacc.c:1645 */ +#line 4378 "awkgram.c" /* yacc.c:1645 */ break; - case 192: -#line 1993 "awkgram.y" /* yacc.c:1645 */ + case 196: +#line 2149 "awkgram.y" /* yacc.c:1645 */ { (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); if ((yyvsp[0]) != NULL) mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); } -#line 4171 "awkgram.c" /* yacc.c:1645 */ +#line 4388 "awkgram.c" /* yacc.c:1645 */ break; - case 193: -#line 2002 "awkgram.y" /* yacc.c:1645 */ + case 197: +#line 2158 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->opcode = Op_postincrement; } -#line 4179 "awkgram.c" /* yacc.c:1645 */ +#line 4396 "awkgram.c" /* yacc.c:1645 */ break; - case 194: -#line 2006 "awkgram.y" /* yacc.c:1645 */ + case 198: +#line 2162 "awkgram.y" /* yacc.c:1645 */ { (yyvsp[0])->opcode = Op_postdecrement; } -#line 4187 "awkgram.c" /* yacc.c:1645 */ +#line 4404 "awkgram.c" /* yacc.c:1645 */ break; - case 195: -#line 2009 "awkgram.y" /* yacc.c:1645 */ + case 199: +#line 2166 "awkgram.y" /* yacc.c:1645 */ { (yyval) = NULL; } -#line 4193 "awkgram.c" /* yacc.c:1645 */ +#line 4410 "awkgram.c" /* yacc.c:1645 */ break; - case 197: -#line 2017 "awkgram.y" /* yacc.c:1645 */ - { yyerrok; } -#line 4199 "awkgram.c" /* yacc.c:1645 */ + case 200: +#line 2170 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); } +#line 4416 "awkgram.c" /* yacc.c:1645 */ break; - case 198: -#line 2021 "awkgram.y" /* yacc.c:1645 */ + case 201: +#line 2174 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); yyerrok; } +#line 4422 "awkgram.c" /* yacc.c:1645 */ + break; + + case 202: +#line 2178 "awkgram.y" /* yacc.c:1645 */ { yyerrok; } -#line 4205 "awkgram.c" /* yacc.c:1645 */ +#line 4428 "awkgram.c" /* yacc.c:1645 */ break; - case 201: -#line 2030 "awkgram.y" /* yacc.c:1645 */ + case 203: +#line 2183 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = NULL; } +#line 4434 "awkgram.c" /* yacc.c:1645 */ + break; + + case 205: +#line 2188 "awkgram.y" /* yacc.c:1645 */ { yyerrok; } -#line 4211 "awkgram.c" /* yacc.c:1645 */ +#line 4440 "awkgram.c" /* yacc.c:1645 */ break; - case 202: -#line 2034 "awkgram.y" /* yacc.c:1645 */ + case 206: +#line 2192 "awkgram.y" /* yacc.c:1645 */ { (yyval) = (yyvsp[0]); yyerrok; } -#line 4217 "awkgram.c" /* yacc.c:1645 */ +#line 4446 "awkgram.c" /* yacc.c:1645 */ break; - case 203: -#line 2038 "awkgram.y" /* yacc.c:1645 */ - { yyerrok; } -#line 4223 "awkgram.c" /* yacc.c:1645 */ + case 207: +#line 2196 "awkgram.y" /* yacc.c:1645 */ + { (yyval) = (yyvsp[0]); yyerrok; } +#line 4452 "awkgram.c" /* yacc.c:1645 */ break; -#line 4227 "awkgram.c" /* yacc.c:1645 */ +#line 4456 "awkgram.c" /* yacc.c:1645 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -4450,7 +4679,7 @@ yyreturn: #endif return yyresult; } -#line 2040 "awkgram.y" /* yacc.c:1903 */ +#line 2198 "awkgram.y" /* yacc.c:1903 */ struct token { @@ -4503,7 +4732,7 @@ static const struct token tokentab[] = { {"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0}, {"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0}, {"END", Op_rule, LEX_END, 0, 0, 0}, -{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, #ifdef ARRAYDEBUG {"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, #endif @@ -4529,8 +4758,8 @@ static const struct token tokentab[] = { {"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)}, {"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0}, {"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0}, -{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, -{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, +{"function", Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, {"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0}, {"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0}, {"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, @@ -4549,6 +4778,7 @@ static const struct token tokentab[] = { {"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)}, {"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0}, {"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_mktime, 0}, +{"namespace", Op_symbol, LEX_NAMESPACE, GAWKX, 0, 0}, {"next", Op_K_next, LEX_NEXT, 0, 0, 0}, {"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0}, {"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)}, @@ -4575,7 +4805,7 @@ static const struct token tokentab[] = { {"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0}, {"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0}, {"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0}, -{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_typeof, 0}, +{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_typeof, 0}, {"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0}, {"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)}, }; @@ -4595,15 +4825,22 @@ static int cur_ring_idx; /* getfname --- return name of a builtin function (for pretty printing) */ const char * -getfname(NODE *(*fptr)(int)) +getfname(NODE *(*fptr)(int), bool prepend_awk) { int i, j; + static char buf[100]; j = sizeof(tokentab) / sizeof(tokentab[0]); /* linear search, no other way to do it */ - for (i = 0; i < j; i++) - if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) + for (i = 0; i < j; i++) { + if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) { + if (prepend_awk && (tokentab[i].flags & GAWKX) != 0) { + sprintf(buf, "awk::%s", tokentab[i].operator); + return buf; + } return tokentab[i].operator; + } + } return NULL; } @@ -4768,6 +5005,9 @@ yyerror(const char *m, ...) char *buf; int count; static char end_of_file_line[] = "(END OF FILE)"; + static char syntax_error[] = "syntax error"; + static size_t syn_err_len = sizeof(syntax_error) - 1; + bool generic_error = (strncmp(m, syntax_error, syn_err_len) == 0); print_included_from(); @@ -4798,7 +5038,11 @@ yyerror(const char *m, ...) bp = thisline + strlen(thisline); } - msg("%.*s", (int) (bp - thisline), thisline); + if (lexeof && mesg == NULL && generic_error) { + msg("%s", end_of_file_line); + mesg = _("source files / command-line arguments must contain complete functions or rules"); + } else + msg("%.*s", (int) (bp - thisline), thisline); va_start(args, m); if (mesg == NULL) @@ -4889,11 +5133,12 @@ mk_program() cp = end_block; else cp = list_merge(begin_block, end_block); - if (program_comment != NULL) { - (void) list_prepend(cp, program_comment); + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; } - if (comment != NULL) - (void) list_append(cp, comment); + (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -4904,6 +5149,16 @@ mk_program() (void) list_merge(cp, beginfile_block); (void) list_merge(cp, endfile_block); + if (outer_comment != NULL) { + cp = list_merge(list_create(outer_comment), cp); + outer_comment = NULL; + } + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; + } + goto out; } else { @@ -4926,12 +5181,16 @@ mk_program() if (begin_block != NULL) cp = list_merge(begin_block, cp); - if (program_comment != NULL) { - (void) list_prepend(cp, program_comment); + if (outer_comment != NULL) { + cp = list_merge(list_create(outer_comment), cp); + outer_comment = NULL; } - if (comment != NULL) { - (void) list_append(cp, comment); + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; } + (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -4939,10 +5198,6 @@ out: /* delete the Op_list, not needed */ tmp = cp->nexti; bcfree(cp); - /* these variables are not used again but zap them anyway. */ - comment = NULL; - function_comment = NULL; - program_comment = NULL; return tmp; #undef begin_block @@ -5117,33 +5372,35 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl /* include_source --- read program from source included using `@include' */ -static int -include_source(INSTRUCTION *file) +static bool +include_source(INSTRUCTION *file, void **srcfile_p) { SRCFILE *s; char *src = file->lextok; int errcode; bool already_included; + *srcfile_p = NULL; + if (do_traditional || do_posix) { error_ln(file->source_line, _("@include is a gawk extension")); - return -1; + return false; } if (strlen(src) == 0) { if (do_lint) lintwarn_ln(file->source_line, _("empty filename after @include")); - return 0; + return true; } s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode); if (s == NULL) { if (already_included) - return 0; + return true; error_ln(file->source_line, _("can't open source file `%s' for reading (%s)"), src, errcode ? strerror(errcode) : _("reason unknown")); - return -1; + return false; } /* save scanner state for the current sourcefile */ @@ -5153,6 +5410,7 @@ include_source(INSTRUCTION *file) sourcefile->lexptr_begin = lexptr_begin; sourcefile->lexeme = lexeme; sourcefile->lasttok = lasttok; + sourcefile->namespace = current_namespace; /* included file becomes the current source */ sourcefile = s; @@ -5162,42 +5420,54 @@ include_source(INSTRUCTION *file) lasttok = 0; lexeof = false; eof_warned = false; - return 0; + current_namespace = awk_namespace; + *srcfile_p = (void *) s; + return true; } /* load_library --- load a shared library */ -static int -load_library(INSTRUCTION *file) +static bool +load_library(INSTRUCTION *file, void **srcfile_p) { SRCFILE *s; char *src = file->lextok; int errcode; bool already_included; + *srcfile_p = NULL; + if (do_traditional || do_posix) { error_ln(file->source_line, _("@load is a gawk extension")); - return -1; + return false; } + if (strlen(src) == 0) { if (do_lint) lintwarn_ln(file->source_line, _("empty filename after @load")); - return 0; + return true; } - s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); - if (s == NULL) { - if (already_included) - return 0; - error_ln(file->source_line, - _("can't open shared library `%s' for reading (%s)"), - src, errcode ? strerror(errcode) : _("reason unknown")); - return -1; + if (do_pretty_print && ! do_profile) { + // create a fake one, don't try to open the file + s = do_add_srcfile(SRC_EXTLIB, src, src, sourcefile); + } else { + s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return true; + error_ln(file->source_line, + _("can't open shared library `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return false; + } + + load_ext(s->fullpath); } - load_ext(s->fullpath); - return 0; + *srcfile_p = (void *) s; + return true; } /* next_sourcefile --- read program from the next source in srcfiles */ @@ -5256,11 +5526,15 @@ next_sourcefile() lexeme = sourcefile->lexeme; sourceline = sourcefile->srclines; source = sourcefile->src; + if (current_namespace != awk_namespace) + efree((char *) current_namespace); + current_namespace = sourcefile->namespace; } else { lexptr = NULL; sourceline = 0; source = NULL; lasttok = 0; + current_namespace = awk_namespace; } } @@ -5506,6 +5780,9 @@ check_bad_char(int c) /* nextc --- get the next input character */ +// For namespaces, -e chunks must be syntactic units. +#define NO_CONTINUE_SOURCE_STRINGS 1 + static int nextc(bool check_for_bad) { @@ -5593,6 +5870,7 @@ again: return END_SRC; } } +#undef NO_CONTINUE_SOURCE_STRINGS /* pushback --- push a character back on the input */ @@ -5605,37 +5883,23 @@ pushback(void) (! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr); } -/* check_comment --- check for block comment */ - -void -check_comment(void) -{ - if (comment != NULL) { - if (first_rule) { - program_comment = comment; - } else - block_comment = comment; - comment = NULL; - } - first_rule = false; -} - /* * get_comment --- collect comment text. * Flag = EOL_COMMENT for end-of-line comments. - * Flag = FULL_COMMENT for self-contained comments. + * Flag = BLOCK_COMMENT for self-contained comments. */ -int -get_comment(int flag) +static int +get_comment(enum commenttype flag, INSTRUCTION **comment_instruction) { int c; int sl; + char *p1; + char *p2; + tok = tokstart; tokadd('#'); sl = sourceline; - char *p1; - char *p2; while (true) { while ((c = nextc(false)) != '\n' && c != END_FILE) { @@ -5671,9 +5935,6 @@ get_comment(int flag) break; } - if (comment != NULL) - prior_comment = comment; - /* remove any trailing blank lines (consecutive \n) from comment */ p1 = tok - 1; p2 = tok - 2; @@ -5683,49 +5944,18 @@ get_comment(int flag) tok--; } - comment = bcalloc(Op_comment, 1, sl); - comment->source_file = source; - comment->memory = make_str_node(tokstart, tok - tokstart, 0); - comment->memory->comment_type = flag; + (*comment_instruction) = bcalloc(Op_comment, 1, sl); + (*comment_instruction)->source_file = source; + (*comment_instruction)->memory = make_str_node(tokstart, tok - tokstart, 0); + (*comment_instruction)->memory->comment_type = flag; 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_to_save->memory->stptr; - l = comment_to_save->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_to_save; - n = function_comment->memory; - function_comment->memory = make_string(p + l + 2, n->stlen - l - 2); - /* create program comment */ - program_comment = bcalloc(Op_comment, 1, sourceline); - program_comment->source_file = comment_to_save->source_file; - p[l + 2] = 0; - program_comment->memory = make_str_node(p, l + 2, 0); - comment_to_save = NULL; - freenode(n); - break; - } - else - l--; - } -} - /* allow_newline --- allow newline after &&, ||, ? and : */ static void -allow_newline(void) +allow_newline(INSTRUCTION **new_comment) { int c; @@ -5737,8 +5967,8 @@ allow_newline(void) } if (c == '#') { if (do_pretty_print && ! do_profile) { - /* collect comment byte code iff doing pretty print but not profiling. */ - c = get_comment(EOL_COMMENT); + /* collect comment byte code iff doing pretty print but not profiling. */ + c = get_comment(EOL_COMMENT, new_comment); } else { while ((c = nextc(false)) != '\n' && c != END_FILE) continue; @@ -5805,6 +6035,7 @@ yylex(void) bool intlstr = false; AWKNUM d; bool collecting_typed_regexp = false; + static int qm_col_count = 0; #define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) @@ -5969,18 +6200,25 @@ retry: return lasttok = NEWLINE; case '#': /* it's a comment */ + yylval = NULL; if (do_pretty_print && ! do_profile) { /* * Collect comment byte code iff doing pretty print * but not profiling. */ + INSTRUCTION *new_comment; + if (lasttok == NEWLINE || lasttok == 0) - c = get_comment(FULL_COMMENT); + c = get_comment(BLOCK_COMMENT, & new_comment); else - c = get_comment(EOL_COMMENT); + c = get_comment(EOL_COMMENT, & new_comment); - if (c == END_FILE) - return lasttok = NEWLINE_EOF; + yylval = new_comment; + + if (c == END_FILE) { + pushback(); + return lasttok = NEWLINE; + } } else { while ((c = nextc(false)) != '\n') { if (c == END_FILE) @@ -6009,7 +6247,10 @@ retry: * Use it at your own risk. We think it's a bad idea, which * is why it's not on by default. */ + yylval = NULL; if (! do_traditional) { + INSTRUCTION *new_comment; + /* strip trailing white-space and/or comment */ while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') continue; @@ -6021,9 +6262,11 @@ retry: lintwarn( _("use of `\\ #...' line continuation is not portable")); } - if (do_pretty_print && ! do_profile) - c = get_comment(EOL_COMMENT); - else { + if (do_pretty_print && ! do_profile) { + c = get_comment(EOL_COMMENT, & new_comment); + yylval = new_comment; + return lasttok = c; + } else { while ((c = nextc(false)) != '\n') if (c == END_FILE) break; @@ -6044,11 +6287,20 @@ retry: } break; - case ':': case '?': + qm_col_count++; + // fall through + case ':': yylval = GET_INSTRUCTION(Op_cond_exp); - if (! do_posix) - allow_newline(); + if (qm_col_count > 0) { + if (! do_posix) { + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + } + if (c == ':') + qm_col_count--; + } return lasttok = c; /* @@ -6470,7 +6722,10 @@ retry: case '&': if ((c = nextc(true)) == '&') { yylval = GET_INSTRUCTION(Op_and); - allow_newline(); + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + return lasttok = LEX_AND; } pushback(); @@ -6480,11 +6735,15 @@ retry: case '|': if ((c = nextc(true)) == '|') { yylval = GET_INSTRUCTION(Op_or); - allow_newline(); + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + return lasttok = LEX_OR; } else if (! do_traditional && c == '&') { yylval = GET_INSTRUCTION(Op_symbol); yylval->redir_type = redirect_twoway; + return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN); } pushback(); @@ -6532,18 +6791,39 @@ retry: while (c != END_FILE && is_identchar(c)) { tokadd(c); c = nextc(true); + + if (! do_traditional && c == ':') { + int peek = nextc(true); + + if (peek == ':') { // saw identifier:: + tokadd(c); + tokadd(c); + c = nextc(true); + } else + pushback(); + // then continue around the loop, c == ':' + } } tokadd('\0'); pushback(); + (void) validate_qualified_name(tokstart); + /* See if it is a special token. */ - if ((mid = check_special(tokstart)) >= 0) { + if ((mid = check_qualified_special(tokstart)) >= 0) { static int warntab[sizeof(tokentab) / sizeof(tokentab[0])]; int class = tokentab[mid].class; - if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL) - && lasttok != '@') - goto out; + switch (class) { + case LEX_EVAL: + case LEX_INCLUDE: + case LEX_LOAD: + case LEX_NAMESPACE: + if (lasttok != '@') + goto out; + default: + break; + } /* allow parameter names to shadow the names of gawk extension built-ins */ if ((tokentab[mid].flags & GAWKX) != 0) { @@ -6555,7 +6835,7 @@ retry: goto out; case FUNC_BODY: /* in body, name must be in symbol table for it to be a parameter */ - if ((f = lookup(tokstart)) != NULL) { + if ((f = lookup(tokstart, false)) != NULL) { if (f->type == Node_builtin_func) break; else @@ -6598,6 +6878,7 @@ retry: continue_allowed++; switch (class) { + case LEX_NAMESPACE: case LEX_INCLUDE: case LEX_LOAD: want_source = true; @@ -6617,7 +6898,7 @@ retry: case LEX_END: case LEX_BEGINFILE: case LEX_ENDFILE: - yylval = bcalloc(tokentab[mid].value, 3, sourceline); + yylval = bcalloc(tokentab[mid].value, 4, sourceline); break; case LEX_FOR: @@ -6674,8 +6955,11 @@ out: yylval->lextok = tokkey; #define SMART_ALECK 1 - if (SMART_ALECK && do_lint - && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { + if (SMART_ALECK + && do_lint + && ! goto_warned + && tolower(tokkey[0]) == 'g' + && strcasecmp(tokkey, "goto") == 0) { goto_warned = true; lintwarn(_("`goto' considered harmful!")); } @@ -6856,10 +7140,20 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) arg->nexti->opcode = Op_push_arg; /* argument may be array */ } - } else if (r->builtin == do_isarray || r->builtin == do_typeof) { + } else if (r->builtin == do_isarray) { + arg = subn->nexti; + if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) + arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ + } else if (r->builtin == do_typeof) { arg = subn->nexti; if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ + if (nexp == 2) { /* 2nd argument there */ + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } #ifdef SUPPLY_INTDIV } else if (r->builtin == do_intdiv #ifdef HAVE_MPFR @@ -7037,7 +7331,7 @@ parms_shadow(INSTRUCTION *pc, bool *shadow) * about all shadowed parameters. */ for (i = 0; i < pcount; i++) { - if (lookup(fp[i].param) != NULL) { + if (lookup(fp[i].param, false) != NULL) { warning( _("function `%s': parameter `%s' shadows global variable"), fname, fp[i].param); @@ -7148,13 +7442,15 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) /* 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; + if (interblock_comment != NULL) { + interblock_comment->source_line = 0; + merge_comments(interblock_comment, fi->comment); + fi->comment = interblock_comment; + interblock_comment = NULL; } - /* add an implicit return at end; + /* + * Add an implicit return at end; * also used by 'return' command in debugger */ @@ -7162,8 +7458,16 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) def->lasti->memory = dupnode(Nnull_string); (void) list_append(def, instruction(Op_K_return)); - if (do_pretty_print) + if (trailing_comment != NULL) { + (void) list_append(def, trailing_comment); + trailing_comment = NULL; + } + + if (do_pretty_print) { + fi[3].nexti = namespace_chain; + namespace_chain = NULL; (void) list_prepend(def, instruction(Op_exec_count)); + } /* fi->opcode = Op_func */ (fi + 1)->firsti = def->nexti; @@ -7195,7 +7499,7 @@ install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist) NODE *r, *f; int pcount = 0; - r = lookup(fname); + r = lookup(fname, true); if (r != NULL) { error_ln(fi->source_line, _("function name `%s' previously defined"), fname); return -1; @@ -7248,7 +7552,10 @@ check_params(char *fname, int pcount, INSTRUCTION *list) error_ln(p->source_line, _("function `%s': can't use special variable `%s' as a function parameter"), fname, name); - } + } else if (strchr(name, ':') != NULL) + error_ln(p->source_line, + _("function `%s': parameter `%s' cannot contain a namespace"), + fname, name); /* check for duplicate parameters */ for (j = 0; j < i; j++) { @@ -7336,22 +7643,19 @@ check_funcs() for (i = 0; i < HASHSIZE; i++) { for (fp = ftable[i]; fp != NULL; fp = fp->next) { -#ifdef REALLYMEAN - /* making this the default breaks old code. sigh. */ - if (fp->defined == 0 && ! fp->extension) { - error( - _("function `%s' called but never defined"), fp->name); - errcount++; - } -#else - if (do_lint && fp->defined == 0 && ! fp->extension) - lintwarn( - _("function `%s' called but never defined"), fp->name); -#endif + if (do_lint && ! fp->extension) { + /* + * Making this not a lint check and + * incrementing * errcount breaks old code. + * Sigh. + */ + if (fp->defined == 0) + lintwarn(_("function `%s' called but never defined"), + fp->name); - if (do_lint && fp->used == 0 && ! fp->extension) { - lintwarn(_("function `%s' defined but never called directly"), - fp->name); + if (fp->used == 0) + lintwarn(_("function `%s' defined but never called directly"), + fp->name); } } } @@ -7395,7 +7699,7 @@ variable(int location, char *name, NODETYPE type) { NODE *r; - if ((r = lookup(name)) != NULL) { + if ((r = lookup(name, true)) != NULL) { if (r->type == Node_func || r->type == Node_ext_func ) error_ln(location, _("function `%s' called with space between name and `(',\nor used as a variable or an array"), r->vname); @@ -7862,24 +8166,31 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) if (rule != Rule) { rp = pattern; - if (do_pretty_print) + if (do_pretty_print) { + rp[3].nexti = namespace_chain; + namespace_chain = NULL; (void) list_append(action, instruction(Op_no_op)); + } (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = action->lasti; (rp + 2)->first_line = pattern->source_line; (rp + 2)->last_line = lastline; - if (block_comment != NULL) { - ip = list_prepend(list_prepend(action, block_comment), rp); - block_comment = NULL; - } else - ip = list_prepend(action, rp); - + ip = list_prepend(action, rp); + if (interblock_comment != NULL) { + ip = list_prepend(ip, interblock_comment); + interblock_comment = NULL; + } } else { - rp = bcalloc(Op_rule, 3, 0); + rp = bcalloc(Op_rule, 4, 0); rp->in_rule = Rule; rp->source_file = source; tp = instruction(Op_no_op); + if (do_pretty_print) { + rp[3].nexti = namespace_chain; + namespace_chain = NULL; + } + if (pattern == NULL) { /* assert(action != NULL); */ if (do_pretty_print) @@ -7899,14 +8210,20 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) (rp + 2)->last_line = find_line(pattern, LAST_LINE); action = list_create(instruction(Op_K_print_rec)); if (do_pretty_print) - (void) list_prepend(action, instruction(Op_exec_count)); + action = list_prepend(action, instruction(Op_exec_count)); } else (rp + 2)->last_line = lastline; + if (interblock_comment != NULL) { // was after previous action + pattern = list_prepend(pattern, interblock_comment); + interblock_comment = NULL; + } + if (do_pretty_print) { - (void) list_prepend(pattern, instruction(Op_exec_count)); - (void) list_prepend(action, instruction(Op_exec_count)); + pattern = list_prepend(pattern, instruction(Op_exec_count)); + action = list_prepend(action, instruction(Op_exec_count)); } + (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = tp; ip = list_append( @@ -8278,8 +8595,9 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, forp->target_break = tbreak; forp->target_continue = tcont; ret = list_prepend(ret, forp); - } /* else - forp is NULL */ + } + /* else + forp is NULL */ return ret; } @@ -8493,26 +8811,6 @@ list_merge(INSTRUCTION *l1, INSTRUCTION *l2) return l1; } -/* add_pending_comment --- add a pending comment to a statement */ - -static inline INSTRUCTION * -add_pending_comment(INSTRUCTION *stmt) -{ - INSTRUCTION *ret = stmt; - - if (prior_comment != NULL) { - if (function_comment != prior_comment) - ret = list_append(stmt, prior_comment); - prior_comment = NULL; - } else if (comment != NULL && comment->memory->comment_type == EOL_COMMENT) { - if (function_comment != comment) - ret = list_append(stmt, comment); - comment = NULL; - } - - return ret; -} - /* See if name is a special token. */ int @@ -8610,6 +8908,9 @@ one_line_close(int fd) builtin_func_t lookup_builtin(const char *name) { + if (strncmp(name, "awk::", 5) == 0) + name += 5; + int mid = check_special(name); if (mid == -1) @@ -8681,9 +8982,6 @@ install_builtins(void) bool is_alpha(int c) { -#ifdef I_DONT_KNOW_WHAT_IM_DOING - return isalpha(c); -#else /* ! I_DONT_KNOW_WHAT_IM_DOING */ switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': @@ -8698,7 +8996,6 @@ is_alpha(int c) return true; } return false; -#endif /* ! I_DONT_KNOW_WHAT_IM_DOING */ } /* is_alnum --- return true for alphanumeric, English only letters */ @@ -8756,3 +9053,258 @@ set_profile_text(NODE *n, const char *str, size_t len) return n; } + +/* + * merge_comments --- merge c2 into c1 and free c2 if successful. + * Allow c2 to be NULL, in which case just merged chained + * comments in c1. + */ + +static void +merge_comments(INSTRUCTION *c1, INSTRUCTION *c2) +{ + assert(c1->opcode == Op_comment); + + if (c1->comment == NULL && c2 == NULL) // nothing to do + return; + + size_t total = c1->memory->stlen; + if (c1->comment != NULL) + total += 1 /* \n */ + c1->comment->memory->stlen; + + if (c2 != NULL) { + assert(c2->opcode == Op_comment); + total += 1 /* \n */ + c2->memory->stlen; + if (c2->comment != NULL) + total += c2->comment->memory->stlen + 1; + } + + char *buffer; + emalloc(buffer, char *, total + 1, "merge_comments"); + + strcpy(buffer, c1->memory->stptr); + if (c1->comment != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c1->comment->memory->stptr); + } + + if (c2 != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c2->memory->stptr); + if (c2->comment != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c2->comment->memory->stptr); + } + + unref(c2->memory); + if (c2->comment != NULL) { + unref(c2->comment->memory); + bcfree(c2->comment); + c2->comment = NULL; + } + bcfree(c2); + } + + c1->memory->comment_type = BLOCK_COMMENT; + free(c1->memory->stptr); + c1->memory->stptr = buffer; + c1->memory->stlen = strlen(buffer); + + // now free everything else + if (c1->comment != NULL) { + unref(c1->comment->memory); + bcfree(c1->comment); + c1->comment = NULL; + } +} + +/* make_braced_statements --- handle `l_brace statements r_brace' with comments */ + +static INSTRUCTION * +make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace) +{ + INSTRUCTION *ip; + + if (stmts == NULL) + ip = list_create(instruction(Op_no_op)); + else + ip = stmts; + + if (lbrace != NULL) { + INSTRUCTION *comment2 = lbrace->comment; + if (comment2 != NULL) { + ip = list_prepend(ip, comment2); + lbrace->comment = NULL; + } + ip = list_prepend(ip, lbrace); + } + + return ip; +} + +/* validate_qualified_name --- make sure that a qualified name is built correctly */ + +/* + * This routine returns upon first error, no need to produce multiple, possibly + * conflicting / confusing error messages. + */ + +bool +validate_qualified_name(char *token) +{ + char *cp, *cp2; + + // no colon, by definition it's well formed + if ((cp = strchr(token, ':')) == NULL) + return true; + + if (do_traditional || do_posix) { + error_ln(sourceline, _("identifier %s: qualified names not allowed in traditional / POSIX mode"), token); + return false; + } + + if (cp[1] != ':') { // could happen from command line + error_ln(sourceline, _("identifier %s: namespace separator is two colons, not one"), token); + return false; + } + + if (! is_letter(cp[2])) { + error_ln(sourceline, + _("qualified identifier `%s' is badly formed"), + token); + return false; + } + + if ((cp2 = strchr(cp+2, ':')) != NULL) { + error_ln(sourceline, + _("identifier `%s': namespace separator can only appear once in a qualified name"), + token); + return false; + } + + return true; +} + +/* check_qualified_special --- decide if a name is special or not */ + +static int +check_qualified_special(char *token) +{ + char *cp; + + if ((cp = strchr(token, ':')) == NULL && current_namespace == awk_namespace) + return check_special(token); + + /* + * Now it's more complicated. Here are the rules. + * + * 1. Namespace name cannot be a standard awk reserved word or function. + * 2. Subordinate part of the name cannot be standard awk reserved word or function. + * 3. If namespace part is explicitly "awk", return result of check_special(). + * 4. Else return -1 (gawk extensions allowed, we check standard awk in step 2). + */ + + const struct token *tok; + int i; + if (cp == NULL) { // namespace not awk, but a simple identifier + i = check_special(token); + if (i < 0) + return i; + + tok = & tokentab[i]; + if ((tok->flags & GAWKX) != 0 && tok->class == LEX_BUILTIN) + return -1; + else + return i; + } + + char *ns, *end, *subname; + ns = token; + *(end = cp) = '\0'; // temporarily turn it into standalone string + subname = end + 2; + + // First check the namespace part + i = check_special(ns); + if (i >= 0 && (tokentab[i].flags & GAWKX) == 0) { + error_ln(sourceline, _("using reserved identifier `%s' as a namespace is not allowed"), ns); + goto done; + } + + // Now check the subordinate part + i = check_special(subname); + if (i >= 0 && (tokentab[i].flags & GAWKX) == 0 && strcmp(ns, "awk") != 0) { + error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname); + goto done; + } + + if (strcmp(ns, "awk") == 0) { + i = check_special(subname); + if (i >= 0) { + if ((tokentab[i].flags & GAWKX) != 0 && tokentab[i].class == LEX_BUILTIN) + ; // gawk additional builtin function, is ok + else + error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname); + } + } else + i = -1; +done: + *end = ':'; + return i; +} + +/* set_namespace --- change the current namespace */ + +static void +set_namespace(INSTRUCTION *ns, INSTRUCTION *comment) +{ + if (ns == NULL) + return; + + if (do_traditional || do_posix) { + error_ln(ns->source_line, _("@namespace is a gawk extension")); + efree(ns->lextok); + bcfree(ns); + return; + } + + if (! is_valid_identifier(ns->lextok)) { + error_ln(ns->source_line, _("namespace name `%s' must meet identifier naming rules"), ns->lextok); + efree(ns->lextok); + bcfree(ns); + return; + } + + int mid = check_special(ns->lextok); + + if (mid >= 0) { + error_ln(ns->source_line, _("using reserved identifier `%s' as a namespace is not allowed"), ns->lextok); + efree(ns->lextok); + bcfree(ns); + return; + } + + if (strcmp(ns->lextok, current_namespace) == 0) + efree(ns->lextok); + else if (strcmp(ns->lextok, awk_namespace) == 0) { + efree(ns->lextok); + current_namespace = awk_namespace; + } else { + if (current_namespace != awk_namespace) + efree((char *) current_namespace); + current_namespace = ns->lextok; + } + + // save info and push on front of list of namespaces seen + INSTRUCTION *new_ns = instruction(Op_K_namespace); + new_ns->comment = comment; + new_ns->ns_name = estrdup(current_namespace, strlen(current_namespace)); + new_ns->nexti = namespace_chain; + namespace_chain = new_ns; + + ns->lextok = NULL; + bcfree(ns); + + namespace_changed = true; + + return; +} @@ -53,11 +53,31 @@ static int isnoeffect(OPCODE type); static INSTRUCTION *make_assignable(INSTRUCTION *ip); static void dumpintlstr(const char *str, size_t len); static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2); -static int include_source(INSTRUCTION *file); -static int load_library(INSTRUCTION *file); +static bool include_source(INSTRUCTION *file, void **srcfile_p); +static bool load_library(INSTRUCTION *file, void **srcfile_p); +static void set_namespace(INSTRUCTION *ns, INSTRUCTION *comment); static void next_sourcefile(void); static char *tokexpand(void); static NODE *set_profile_text(NODE *n, const char *str, size_t len); +static int check_qualified_special(char *token); +static INSTRUCTION *trailing_comment; +static INSTRUCTION *outer_comment; +static INSTRUCTION *interblock_comment; +static INSTRUCTION *pending_comment; +static INSTRUCTION *namespace_chain; + +#ifdef DEBUG_COMMENTS +static void +debug_print_comment_s(const char *name, INSTRUCTION *comment, int line) +{ + if (comment != NULL) + fprintf(stderr, "%d: %s: <%.*s>\n", line, name, + (int) (comment->memory->stlen - 1), + comment->memory->stptr); +} +#define debug_print_comment(comment) \ + debug_print_comment_s(# comment, comment, __LINE__) +#endif #define instruction(t) bcalloc(t, 1, 0) @@ -84,8 +104,8 @@ 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 void check_comment(void); +static void merge_comments(INSTRUCTION *c1, INSTRUCTION *c2); +static INSTRUCTION *make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace); static void add_sign_to_num(NODE *n, char sign); static bool at_seen = false; @@ -142,6 +162,10 @@ extern INSTRUCTION *rule_list; extern int max_args; extern NODE **args_array; +const char awk_namespace[] = "awk"; +const char *current_namespace = awk_namespace; +bool namespace_changed = false; + static INSTRUCTION *rule_block[sizeof(ruletab)]; static INSTRUCTION *ip_rec; @@ -152,21 +176,10 @@ static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; INSTRUCTION *main_beginfile; -static INSTRUCTION *comment = NULL; -static INSTRUCTION *prior_comment = NULL; -static INSTRUCTION *comment_to_save = NULL; -static INSTRUCTION *program_comment = NULL; -static INSTRUCTION *function_comment = NULL; -static INSTRUCTION *block_comment = NULL; - -static bool func_first = true; -static bool first_rule = 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); static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2); -static inline INSTRUCTION *add_pending_comment(INSTRUCTION *stmt); extern double fmod(double x, double y); @@ -187,7 +200,7 @@ extern double fmod(double x, double y); %token LEX_AND LEX_OR INCREMENT DECREMENT %token LEX_BUILTIN LEX_LENGTH %token LEX_EOF -%token LEX_INCLUDE LEX_EVAL LEX_LOAD +%token LEX_INCLUDE LEX_EVAL LEX_LOAD LEX_NAMESPACE %token NEWLINE /* Lowest to highest */ @@ -214,12 +227,22 @@ extern double fmod(double x, double y); program : /* empty */ + { $$ = NULL; } | program rule { rule = 0; yyerrok; } | program nls + { + if ($2 != NULL) { + if ($1 == NULL) + outer_comment = $2; + else + interblock_comment = $2; + } + $$ = $1; + } | program LEX_EOF { next_sourcefile(); @@ -239,7 +262,10 @@ rule : pattern action { (void) append_rule($1, $2); - first_rule = false; + if (pending_comment != NULL) { + interblock_comment = pending_comment; + pending_comment = NULL; + } } | pattern statement_term { @@ -249,26 +275,51 @@ rule } else if ($1 == NULL) { msg(_("each rule must have a pattern or an action part")); errcount++; - } else /* pattern rule with non-empty pattern */ + } else { /* pattern rule with non-empty pattern */ + if ($2 != NULL) + list_append($1, $2); (void) append_rule($1, NULL); + } } | function_prologue action { in_function = NULL; (void) mk_function($1, $2); want_param_names = DONT_CHECK; + if (pending_comment != NULL) { + interblock_comment = pending_comment; + pending_comment = NULL; + } yyerrok; } | '@' LEX_INCLUDE source statement_term { want_source = false; at_seen = false; + if ($3 != NULL && $4 != NULL) { + SRCFILE *s = (SRCFILE *) $3; + s->comment = $4; + } yyerrok; } | '@' LEX_LOAD library statement_term { want_source = false; at_seen = false; + if ($3 != NULL && $4 != NULL) { + SRCFILE *s = (SRCFILE *) $3; + s->comment = $4; + } + yyerrok; + } + | '@' LEX_NAMESPACE namespace statement_term + { + want_source = false; + at_seen = false; + + // this frees $3 storage in all cases + set_namespace($3, $4); + yyerrok; } ; @@ -276,11 +327,13 @@ rule source : FILENAME { - if (include_source($1) < 0) + void *srcfile = NULL; + + if (! include_source($1, & srcfile)) YYABORT; efree($1->lextok); bcfree($1); - $$ = NULL; + $$ = (INSTRUCTION *) srcfile; } | FILENAME error { $$ = NULL; } @@ -291,11 +344,13 @@ source library : FILENAME { - if (load_library($1) < 0) + void *srcfile; + + if (! load_library($1, & srcfile)) YYABORT; efree($1->lextok); bcfree($1); - $$ = NULL; + $$ = (INSTRUCTION *) srcfile; } | FILENAME error { $$ = NULL; } @@ -303,98 +358,90 @@ library { $$ = NULL; } ; +namespace + : FILENAME + { $$ = $1; } + | FILENAME error + { $$ = NULL; } + | error + { $$ = NULL; } + ; + pattern : /* empty */ { rule = Rule; - if (comment != NULL) { - $$ = list_create(comment); - comment = NULL; - } else - $$ = NULL; + $$ = NULL; } | exp { rule = Rule; - if (comment != NULL) { - $$ = list_prepend($1, comment); - comment = NULL; - } else - $$ = $1; } - | exp ',' opt_nls exp + | exp comma exp { INSTRUCTION *tp; add_lint($1, LINT_assign_in_cond); - add_lint($4, LINT_assign_in_cond); + add_lint($3, LINT_assign_in_cond); tp = instruction(Op_no_op); list_prepend($1, bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); $1->nexti->triggered = false; - $1->nexti->target_jmp = $4->nexti; + $1->nexti->target_jmp = $3->nexti; list_append($1, instruction(Op_cond_pair)); $1->lasti->line_range = $1->nexti; $1->lasti->target_jmp = tp; - list_append($4, instruction(Op_cond_pair)); - $4->lasti->line_range = $1->nexti; - $4->lasti->target_jmp = tp; + list_append($3, instruction(Op_cond_pair)); + $3->lasti->line_range = $1->nexti; + $3->lasti->target_jmp = tp; if (do_pretty_print) { ($1->nexti + 1)->condpair_left = $1->lasti; - ($1->nexti + 1)->condpair_right = $4->lasti; + ($1->nexti + 1)->condpair_right = $3->lasti; } - if (comment != NULL) { - $$ = list_append(list_merge(list_prepend($1, comment), $4), tp); - comment = NULL; - } else - $$ = list_append(list_merge($1, $4), tp); + /* Put any comments in front of the range expression */ + if ($2 != NULL) + $$ = list_append(list_merge(list_prepend($1, $2), $3), tp); + else + $$ = list_append(list_merge($1, $3), tp); rule = Rule; } | 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")); $1->in_rule = rule = BEGIN; $1->source_file = source; - check_comment(); $$ = $1; } | 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")); $1->in_rule = rule = END; $1->source_file = source; - check_comment(); $$ = $1; } | LEX_BEGINFILE { - func_first = false; $1->in_rule = rule = BEGINFILE; $1->source_file = source; - check_comment(); $$ = $1; } | LEX_ENDFILE { - func_first = false; $1->in_rule = rule = ENDFILE; $1->source_file = source; - check_comment(); $$ = $1; } ; @@ -402,11 +449,17 @@ pattern action : l_brace statements r_brace opt_semi opt_nls { - INSTRUCTION *ip; - if ($2 == NULL) - ip = list_create(instruction(Op_no_op)); - else - ip = $2; + INSTRUCTION *ip = make_braced_statements($1, $2, $3); + + if ($3 != NULL && $5 != NULL) { + merge_comments($3, $5); + pending_comment = $3; + } else if ($3 != NULL) { + pending_comment = $3; + } else if ($5 != NULL) { + pending_comment = $5; + } + $$ = ip; } ; @@ -437,33 +490,21 @@ lex_builtin function_prologue : LEX_FUNCTION func_name '(' { want_param_names = FUNC_HEADER; } 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 (prior_comment != NULL) { - comment_to_save = prior_comment; - prior_comment = NULL; - } else if (comment != NULL) { - comment_to_save = comment; - comment = NULL; - } else - comment_to_save = NULL; - - if (comment_to_save != NULL && func_first - && strstr(comment_to_save->memory->stptr, "\n\n") != NULL) - split_comment(); - - /* save any other pre-function comment as function comment */ - if (comment_to_save != NULL) { - function_comment = comment_to_save; - comment_to_save = NULL; + INSTRUCTION *func_comment = NULL; + // Merge any comments found in the parameter list with those + // following the function header, associate the whole shebang + // with the function as one block comment. + if ($5 != NULL && $5->comment != NULL) { + if ($7 != NULL) { + merge_comments($5->comment, $7); + } + func_comment = $5->comment; + } else if ($7 != NULL) { + func_comment = $7; } - func_first = false; + $1->source_file = source; + $1->comment = func_comment; if (install_function($2->lextok, $1, $5) < 0) YYABORT; in_function = $2->lextok; @@ -536,61 +577,25 @@ a_slash statements : /* empty */ - { - if (prior_comment != NULL) { - $$ = list_create(prior_comment); - prior_comment = NULL; - } else if (comment != NULL) { - $$ = list_create(comment); - comment = NULL; - } else - $$ = NULL; - } + { $$ = NULL; } | statements statement { if ($2 == NULL) { - if (prior_comment != NULL) { - $$ = list_append($1, prior_comment); - prior_comment = NULL; - if (comment != NULL) { - $$ = list_append($$, comment); - comment = NULL; - } - } else if (comment != NULL) { - $$ = list_append($1, comment); - comment = NULL; - } else - $$ = $1; + $$ = $1; } else { add_lint($2, LINT_no_effect); if ($1 == NULL) { - if (prior_comment != NULL) { - $$ = list_append($2, prior_comment); - prior_comment = NULL; - if (comment != NULL) { - $$ = list_append($$, comment); - comment = NULL; - } - } else if (comment != NULL) { - $$ = list_append($2, comment); - comment = NULL; - } else - $$ = $2; + $$ = $2; } else { - if (prior_comment != NULL) { - list_append($2, prior_comment); - prior_comment = NULL; - if (comment != NULL) { - list_append($2, comment); - comment = NULL; - } - } else if (comment != NULL) { - list_append($2, comment); - comment = NULL; - } $$ = list_merge($1, $2); } } + + if (trailing_comment != NULL) { + $$ = list_append($$, trailing_comment); + trailing_comment = NULL; + } + yyerrok; } | statements error @@ -598,15 +603,27 @@ statements ; statement_term - : nls - | semi opt_nls + : nls { $$ = $1; } + | semi opt_nls { $$ = $2; } ; statement : semi opt_nls - { $$ = NULL; } + { + if ($2 != NULL) { + INSTRUCTION *ip; + + merge_comments($2, NULL); + ip = list_create(instruction(Op_no_op)); + $$ = list_append(ip, $2); + } else + $$ = NULL; + } | l_brace statements r_brace - { $$ = $2; } + { + trailing_comment = $3; // NULL or comment + $$ = make_braced_statements($1, $2, $3); + } | if_statement { if (do_pretty_print) @@ -632,8 +649,9 @@ statement if ($7 != NULL) { curr = $7->nexti; bcfree($7); /* Op_list */ - } /* else - curr = NULL; */ + } + /* else + curr = NULL; */ for (; curr != NULL; curr = nextc) { INSTRUCTION *caseexp = curr->case_exp; @@ -689,16 +707,33 @@ statement ip = $3; if (do_pretty_print) { + // first merge comments + INSTRUCTION *head_comment = NULL; + + if ($5 != NULL && $6 != NULL) { + merge_comments($5, $6); + head_comment = $5; + } else if ($5 != NULL) + head_comment = $5; + else + head_comment = $6; + + $1->comment = head_comment; + (void) list_prepend(ip, $1); (void) list_prepend(ip, instruction(Op_exec_count)); $1->target_break = tbreak; ($1 + 1)->switch_start = cexp->nexti; ($1 + 1)->switch_end = cexp->lasti; - }/* else - $1 is NULL */ + ($1 + 1)->switch_end->comment = $9; + } + /* else + $1 is NULL */ (void) list_append(cexp, dflt); (void) list_merge(ip, cexp); + if ($8 != NULL) + (void) list_append(cstmt, $8); $$ = list_merge(ip, cstmt); break_allowed--; @@ -733,8 +768,17 @@ statement $1->target_continue = tcont; ($1 + 1)->while_body = ip->lasti; (void) list_prepend(ip, $1); - }/* else - $1 is NULL */ + } + /* else + $1 is NULL */ + + if ($5 != NULL) { + if ($6 == NULL) + $6 = list_create(instruction(Op_no_op)); + + $5->memory->comment_type = BLOCK_COMMENT; + $6 = list_prepend($6, $5); + } if ($6 != NULL) (void) list_merge(ip, $6); @@ -769,8 +813,13 @@ statement ip = list_merge($3, $6); else ip = list_prepend($6, instruction(Op_no_op)); + + if ($2 != NULL) + (void) list_prepend(ip, $2); + if (do_pretty_print) (void) list_prepend(ip, instruction(Op_exec_count)); + (void) list_append(ip, instruction(Op_jmp_true)); ip->lasti->target_jmp = ip->nexti; $$ = list_append(ip, tbreak); @@ -785,7 +834,10 @@ statement ($1 + 1)->doloop_cond = tcont; $$ = list_prepend(ip, $1); bcfree($4); - } /* else + if ($8 != NULL) + $1->comment = $8; + } + /* else $1 and $4 are NULLs */ } | LEX_FOR '(' NAME LEX_IN simple_variable r_paren opt_nls statement @@ -801,7 +853,8 @@ statement && strcmp($8->nexti->memory->vname, var_name) == 0 ) { - /* Efficiency hack. Recognize the special case of + /* + * Efficiency hack. Recognize the special case of * * for (iggy in foo) * delete foo[iggy] @@ -833,6 +886,10 @@ statement bcfree($3); bcfree($4); bcfree($5); + if ($7 != NULL) { + merge_comments($7, NULL); + $8 = list_prepend($8, $7); + } $$ = $8; } else goto regular_loop; @@ -867,8 +924,9 @@ regular_loop: $1->target_continue = tcont; $1->target_break = tbreak; (void) list_append(ip, $1); - } /* else - $1 is NULL */ + } + /* else + $1 is NULL */ /* add update_FOO instruction if necessary */ if ($4->array_var->type == Node_var && $4->array_var->var_update) { @@ -889,8 +947,15 @@ regular_loop: ($1 + 1)->forloop_body = ip->lasti; } - if ($8 != NULL) + if ($7 != NULL) + merge_comments($7, NULL); + + if ($8 != NULL) { + if ($7 != NULL) + $8 = list_prepend($8, $7); (void) list_merge(ip, $8); + } else if ($7 != NULL) + (void) list_append(ip, $7); (void) list_append(ip, instruction(Op_jmp)); ip->lasti->target_jmp = $4; @@ -903,6 +968,20 @@ regular_loop: } | LEX_FOR '(' opt_simple_stmt semi opt_nls exp semi opt_nls opt_simple_stmt r_paren opt_nls statement { + if ($5 != NULL) { + merge_comments($5, NULL); + $1->comment = $5; + } + if ($8 != NULL) { + merge_comments($8, NULL); + if ($1->comment == NULL) { + $8->memory->comment_type = FOR_COMMENT; + $1->comment = $8; + } else + $1->comment->comment = $8; + } + if ($11 != NULL) + $12 = list_prepend($12, $11); $$ = mk_for_loop($1, $3, $6, $9, $12); break_allowed--; @@ -910,6 +989,20 @@ regular_loop: } | LEX_FOR '(' opt_simple_stmt semi opt_nls semi opt_nls opt_simple_stmt r_paren opt_nls statement { + if ($5 != NULL) { + merge_comments($5, NULL); + $1->comment = $5; + } + if ($7 != NULL) { + merge_comments($7, NULL); + if ($1->comment == NULL) { + $7->memory->comment_type = FOR_COMMENT; + $1->comment = $7; + } else + $1->comment->comment = $7; + } + if ($10 != NULL) + $11 = list_prepend($11, $10); $$ = mk_for_loop($1, $3, (INSTRUCTION *) NULL, $8, $11); break_allowed--; @@ -921,7 +1014,6 @@ regular_loop: $$ = list_prepend($1, instruction(Op_exec_count)); else $$ = $1; - $$ = add_pending_comment($$); } ; @@ -933,8 +1025,8 @@ non_compound_stmt _("`break' is not allowed outside a loop or switch")); $1->target_jmp = NULL; $$ = list_create($1); - $$ = add_pending_comment($$); - + if ($2 != NULL) + $$ = list_append($$, $2); } | LEX_CONTINUE statement_term { @@ -943,8 +1035,8 @@ non_compound_stmt _("`continue' is not allowed outside a loop")); $1->target_jmp = NULL; $$ = list_create($1); - $$ = add_pending_comment($$); - + if ($2 != NULL) + $$ = list_append($$, $2); } | LEX_NEXT statement_term { @@ -954,7 +1046,8 @@ non_compound_stmt _("`next' used in %s action"), ruletab[rule]); $1->target_jmp = ip_rec; $$ = list_create($1); - $$ = add_pending_comment($$); + if ($2 != NULL) + $$ = list_append($$, $2); } | LEX_NEXTFILE statement_term { @@ -966,7 +1059,8 @@ non_compound_stmt $1->target_newfile = ip_newfile; $1->target_endfile = ip_endfile; $$ = list_create($1); - $$ = add_pending_comment($$); + if ($2 != NULL) + $$ = list_append($$, $2); } | LEX_EXIT opt_exp statement_term { @@ -982,7 +1076,8 @@ non_compound_stmt $$->nexti->memory = dupnode(Nnull_string); } else $$ = list_append($2, $1); - $$ = add_pending_comment($$); + if ($3 != NULL) + $$ = list_append($$, $3); } | LEX_RETURN { @@ -995,10 +1090,16 @@ non_compound_stmt $$->nexti->memory = dupnode(Nnull_string); } else $$ = list_append($3, $1); - - $$ = add_pending_comment($$); + if ($4 != NULL) + $$ = list_append($$, $4); } | simple_stmt statement_term + { + if ($2 != NULL) + $$ = list_append($1, $2); + else + $$ = $1; + } ; /* @@ -1018,7 +1119,7 @@ simple_stmt * which is faster for these two cases. */ - if ($1->opcode == Op_K_print && + if (do_optimize && $1->opcode == Op_K_print && ($3 == NULL || ($3->lasti->opcode == Op_field_spec && $3->nexti->nexti->nexti == $3->lasti @@ -1106,7 +1207,6 @@ regular_print: } } } - $$ = add_pending_comment($$); } | LEX_DELETE NAME { sub_counter = 0; } delete_subscript_list @@ -1141,7 +1241,6 @@ regular_print: $1->expr_count = sub_counter; $$ = list_append(list_append($4, $2), $1); } - $$ = add_pending_comment($$); } | LEX_DELETE '(' NAME ')' /* @@ -1172,12 +1271,10 @@ regular_print: else if ($3->memory == func_table) fatal(_("`delete' is not allowed with FUNCTAB")); } - $$ = add_pending_comment($$); } | exp { $$ = optimize_assignment($1); - $$ = add_pending_comment($$); } ; @@ -1212,6 +1309,7 @@ case_statement (void) list_prepend(casestmt, instruction(Op_exec_count)); $1->case_exp = $2; $1->case_stmt = casestmt; + $1->comment = $4; bcfree($3); $$ = $1; } @@ -1224,6 +1322,7 @@ case_statement (void) list_prepend(casestmt, instruction(Op_exec_count)); bcfree($2); $1->case_stmt = casestmt; + $1->comment = $3; $$ = $1; } ; @@ -1305,23 +1404,51 @@ output_redir if_statement : LEX_IF '(' exp r_paren opt_nls statement { + if ($5 != NULL) + $1->comment = $5; $$ = mk_condition($3, $1, $6, NULL, NULL); } | LEX_IF '(' exp r_paren opt_nls statement LEX_ELSE opt_nls statement { + if ($5 != NULL) + $1->comment = $5; + if ($8 != NULL) + $7->comment = $8; $$ = mk_condition($3, $1, $6, $7, $9); } ; nls : NEWLINE + { + $$ = $1; + } | nls NEWLINE + { + if ($1 != NULL && $2 != NULL) { + if ($1->memory->comment_type == EOL_COMMENT) { + assert($2->memory->comment_type == BLOCK_COMMENT); + $1->comment = $2; // chain them + } else { + merge_comments($1, $2); + } + + $$ = $1; + } else if ($1 != NULL) { + $$ = $1; + } else if ($2 != NULL) { + $$ = $2; + } else + $$ = NULL; + } ; opt_nls : /* empty */ + { $$ = NULL; } | nls + { $$ = $1; } ; input_redir @@ -1350,9 +1477,17 @@ param_list | param_list comma NAME { if ($1 != NULL && $3 != NULL) { - $3->param_count = $1->lasti->param_count + 1; + $3->param_count = $1->lasti->param_count + 1; $$ = list_append($1, $3); yyerrok; + + // newlines are allowed after commas, catch any comments + if ($2 != NULL) { + if ($1->comment != NULL) + merge_comments($1->comment, $2); + else + $1->comment = $2; + } } else $$ = NULL; } @@ -1384,6 +1519,8 @@ expression_list { $$ = mk_expression_list(NULL, $1); } | expression_list comma exp { + if ($2 != NULL) + $1->lasti->comment = $2; $$ = mk_expression_list($1, $3); yyerrok; } @@ -1405,6 +1542,8 @@ expression_list | expression_list comma error { /* Ditto */ + if ($2 != NULL) + $1->lasti->comment = $2; $$ = $1; } ; @@ -1421,6 +1560,8 @@ fcall_expression_list { $$ = mk_expression_list(NULL, $1); } | fcall_expression_list comma fcall_exp { + if ($2 != NULL) + $1->lasti->comment = $2; $$ = mk_expression_list($1, $3); yyerrok; } @@ -1442,6 +1583,8 @@ fcall_expression_list | fcall_expression_list comma error { /* Ditto */ + if ($2 != NULL) + $1->comment = $2; $$ = $1; } ; @@ -1863,9 +2006,21 @@ direct_func_call : FUNC_CALL '(' opt_fcall_expression_list r_paren { NODE *n; + const char *name = $1->func_name; + + if (current_namespace != awk_namespace && strchr(name, ':') == NULL) { + size_t len = strlen(current_namespace) + 2 + strlen(name) + 1; + char *buf; + + emalloc(buf, char *, len, "direct_func_call"); + sprintf(buf, "%s::%s", current_namespace, name); + + efree((void *) $1->func_name); + $1->func_name = buf; + } if (! at_seen) { - n = lookup($1->func_name); + n = lookup($1->func_name, true); if (n != NULL && n->type != Node_func && n->type != Node_ext_func) { error_ln($1->source_line, @@ -1873,6 +2028,7 @@ direct_func_call $1->func_name); } } + param_sanity($3); $1->opcode = Op_func_call; $1->func_body = NULL; @@ -2006,15 +2162,16 @@ opt_incdec { $1->opcode = Op_postdecrement; } - | /* empty */ { $$ = NULL; } + | /* empty */ + { $$ = NULL; } ; l_brace - : '{' opt_nls + : '{' opt_nls { $$ = $2; } ; r_brace - : '}' opt_nls { yyerrok; } + : '}' opt_nls { $$ = $2; yyerrok; } ; r_paren @@ -2023,6 +2180,7 @@ r_paren opt_semi : /* empty */ + { $$ = NULL; } | semi ; @@ -2035,7 +2193,7 @@ colon ; comma - : ',' opt_nls { yyerrok; } + : ',' opt_nls { $$ = $2; yyerrok; } ; %% @@ -2089,7 +2247,7 @@ static const struct token tokentab[] = { {"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0}, {"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0}, {"END", Op_rule, LEX_END, 0, 0, 0}, -{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, #ifdef ARRAYDEBUG {"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, #endif @@ -2115,8 +2273,8 @@ static const struct token tokentab[] = { {"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)}, {"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0}, {"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0}, -{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, -{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, +{"function", Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, {"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0}, {"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0}, {"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, @@ -2135,6 +2293,7 @@ static const struct token tokentab[] = { {"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)}, {"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0}, {"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_mktime, 0}, +{"namespace", Op_symbol, LEX_NAMESPACE, GAWKX, 0, 0}, {"next", Op_K_next, LEX_NEXT, 0, 0, 0}, {"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0}, {"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)}, @@ -2161,7 +2320,7 @@ static const struct token tokentab[] = { {"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0}, {"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0}, {"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0}, -{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_typeof, 0}, +{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_typeof, 0}, {"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0}, {"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)}, }; @@ -2181,15 +2340,22 @@ static int cur_ring_idx; /* getfname --- return name of a builtin function (for pretty printing) */ const char * -getfname(NODE *(*fptr)(int)) +getfname(NODE *(*fptr)(int), bool prepend_awk) { int i, j; + static char buf[100]; j = sizeof(tokentab) / sizeof(tokentab[0]); /* linear search, no other way to do it */ - for (i = 0; i < j; i++) - if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) + for (i = 0; i < j; i++) { + if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) { + if (prepend_awk && (tokentab[i].flags & GAWKX) != 0) { + sprintf(buf, "awk::%s", tokentab[i].operator); + return buf; + } return tokentab[i].operator; + } + } return NULL; } @@ -2354,6 +2520,9 @@ yyerror(const char *m, ...) char *buf; int count; static char end_of_file_line[] = "(END OF FILE)"; + static char syntax_error[] = "syntax error"; + static size_t syn_err_len = sizeof(syntax_error) - 1; + bool generic_error = (strncmp(m, syntax_error, syn_err_len) == 0); print_included_from(); @@ -2384,7 +2553,11 @@ yyerror(const char *m, ...) bp = thisline + strlen(thisline); } - msg("%.*s", (int) (bp - thisline), thisline); + if (lexeof && mesg == NULL && generic_error) { + msg("%s", end_of_file_line); + mesg = _("source files / command-line arguments must contain complete functions or rules"); + } else + msg("%.*s", (int) (bp - thisline), thisline); va_start(args, m); if (mesg == NULL) @@ -2475,11 +2648,12 @@ mk_program() cp = end_block; else cp = list_merge(begin_block, end_block); - if (program_comment != NULL) { - (void) list_prepend(cp, program_comment); + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; } - if (comment != NULL) - (void) list_append(cp, comment); + (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2490,6 +2664,16 @@ mk_program() (void) list_merge(cp, beginfile_block); (void) list_merge(cp, endfile_block); + if (outer_comment != NULL) { + cp = list_merge(list_create(outer_comment), cp); + outer_comment = NULL; + } + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; + } + goto out; } else { @@ -2512,12 +2696,16 @@ mk_program() if (begin_block != NULL) cp = list_merge(begin_block, cp); - if (program_comment != NULL) { - (void) list_prepend(cp, program_comment); + if (outer_comment != NULL) { + cp = list_merge(list_create(outer_comment), cp); + outer_comment = NULL; } - if (comment != NULL) { - (void) list_append(cp, comment); + + if (interblock_comment != NULL) { + (void) list_append(cp, interblock_comment); + interblock_comment = NULL; } + (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2525,10 +2713,6 @@ out: /* delete the Op_list, not needed */ tmp = cp->nexti; bcfree(cp); - /* these variables are not used again but zap them anyway. */ - comment = NULL; - function_comment = NULL; - program_comment = NULL; return tmp; #undef begin_block @@ -2703,33 +2887,35 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl /* include_source --- read program from source included using `@include' */ -static int -include_source(INSTRUCTION *file) +static bool +include_source(INSTRUCTION *file, void **srcfile_p) { SRCFILE *s; char *src = file->lextok; int errcode; bool already_included; + *srcfile_p = NULL; + if (do_traditional || do_posix) { error_ln(file->source_line, _("@include is a gawk extension")); - return -1; + return false; } if (strlen(src) == 0) { if (do_lint) lintwarn_ln(file->source_line, _("empty filename after @include")); - return 0; + return true; } s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode); if (s == NULL) { if (already_included) - return 0; + return true; error_ln(file->source_line, _("can't open source file `%s' for reading (%s)"), src, errcode ? strerror(errcode) : _("reason unknown")); - return -1; + return false; } /* save scanner state for the current sourcefile */ @@ -2739,6 +2925,7 @@ include_source(INSTRUCTION *file) sourcefile->lexptr_begin = lexptr_begin; sourcefile->lexeme = lexeme; sourcefile->lasttok = lasttok; + sourcefile->namespace = current_namespace; /* included file becomes the current source */ sourcefile = s; @@ -2748,42 +2935,54 @@ include_source(INSTRUCTION *file) lasttok = 0; lexeof = false; eof_warned = false; - return 0; + current_namespace = awk_namespace; + *srcfile_p = (void *) s; + return true; } /* load_library --- load a shared library */ -static int -load_library(INSTRUCTION *file) +static bool +load_library(INSTRUCTION *file, void **srcfile_p) { SRCFILE *s; char *src = file->lextok; int errcode; bool already_included; + *srcfile_p = NULL; + if (do_traditional || do_posix) { error_ln(file->source_line, _("@load is a gawk extension")); - return -1; + return false; } + if (strlen(src) == 0) { if (do_lint) lintwarn_ln(file->source_line, _("empty filename after @load")); - return 0; + return true; } - s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); - if (s == NULL) { - if (already_included) - return 0; - error_ln(file->source_line, - _("can't open shared library `%s' for reading (%s)"), - src, errcode ? strerror(errcode) : _("reason unknown")); - return -1; + if (do_pretty_print && ! do_profile) { + // create a fake one, don't try to open the file + s = do_add_srcfile(SRC_EXTLIB, src, src, sourcefile); + } else { + s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return true; + error_ln(file->source_line, + _("can't open shared library `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return false; + } + + load_ext(s->fullpath); } - load_ext(s->fullpath); - return 0; + *srcfile_p = (void *) s; + return true; } /* next_sourcefile --- read program from the next source in srcfiles */ @@ -2842,11 +3041,15 @@ next_sourcefile() lexeme = sourcefile->lexeme; sourceline = sourcefile->srclines; source = sourcefile->src; + if (current_namespace != awk_namespace) + efree((char *) current_namespace); + current_namespace = sourcefile->namespace; } else { lexptr = NULL; sourceline = 0; source = NULL; lasttok = 0; + current_namespace = awk_namespace; } } @@ -3092,6 +3295,9 @@ check_bad_char(int c) /* nextc --- get the next input character */ +// For namespaces, -e chunks must be syntactic units. +#define NO_CONTINUE_SOURCE_STRINGS 1 + static int nextc(bool check_for_bad) { @@ -3179,6 +3385,7 @@ again: return END_SRC; } } +#undef NO_CONTINUE_SOURCE_STRINGS /* pushback --- push a character back on the input */ @@ -3191,37 +3398,23 @@ pushback(void) (! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr); } -/* check_comment --- check for block comment */ - -void -check_comment(void) -{ - if (comment != NULL) { - if (first_rule) { - program_comment = comment; - } else - block_comment = comment; - comment = NULL; - } - first_rule = false; -} - /* * get_comment --- collect comment text. * Flag = EOL_COMMENT for end-of-line comments. - * Flag = FULL_COMMENT for self-contained comments. + * Flag = BLOCK_COMMENT for self-contained comments. */ -int -get_comment(int flag) +static int +get_comment(enum commenttype flag, INSTRUCTION **comment_instruction) { int c; int sl; + char *p1; + char *p2; + tok = tokstart; tokadd('#'); sl = sourceline; - char *p1; - char *p2; while (true) { while ((c = nextc(false)) != '\n' && c != END_FILE) { @@ -3257,9 +3450,6 @@ get_comment(int flag) break; } - if (comment != NULL) - prior_comment = comment; - /* remove any trailing blank lines (consecutive \n) from comment */ p1 = tok - 1; p2 = tok - 2; @@ -3269,49 +3459,18 @@ get_comment(int flag) tok--; } - comment = bcalloc(Op_comment, 1, sl); - comment->source_file = source; - comment->memory = make_str_node(tokstart, tok - tokstart, 0); - comment->memory->comment_type = flag; + (*comment_instruction) = bcalloc(Op_comment, 1, sl); + (*comment_instruction)->source_file = source; + (*comment_instruction)->memory = make_str_node(tokstart, tok - tokstart, 0); + (*comment_instruction)->memory->comment_type = flag; 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_to_save->memory->stptr; - l = comment_to_save->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_to_save; - n = function_comment->memory; - function_comment->memory = make_string(p + l + 2, n->stlen - l - 2); - /* create program comment */ - program_comment = bcalloc(Op_comment, 1, sourceline); - program_comment->source_file = comment_to_save->source_file; - p[l + 2] = 0; - program_comment->memory = make_str_node(p, l + 2, 0); - comment_to_save = NULL; - freenode(n); - break; - } - else - l--; - } -} - /* allow_newline --- allow newline after &&, ||, ? and : */ static void -allow_newline(void) +allow_newline(INSTRUCTION **new_comment) { int c; @@ -3323,8 +3482,8 @@ allow_newline(void) } if (c == '#') { if (do_pretty_print && ! do_profile) { - /* collect comment byte code iff doing pretty print but not profiling. */ - c = get_comment(EOL_COMMENT); + /* collect comment byte code iff doing pretty print but not profiling. */ + c = get_comment(EOL_COMMENT, new_comment); } else { while ((c = nextc(false)) != '\n' && c != END_FILE) continue; @@ -3391,6 +3550,7 @@ yylex(void) bool intlstr = false; AWKNUM d; bool collecting_typed_regexp = false; + static int qm_col_count = 0; #define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) @@ -3555,18 +3715,25 @@ retry: return lasttok = NEWLINE; case '#': /* it's a comment */ + yylval = NULL; if (do_pretty_print && ! do_profile) { /* * Collect comment byte code iff doing pretty print * but not profiling. */ + INSTRUCTION *new_comment; + if (lasttok == NEWLINE || lasttok == 0) - c = get_comment(FULL_COMMENT); + c = get_comment(BLOCK_COMMENT, & new_comment); else - c = get_comment(EOL_COMMENT); + c = get_comment(EOL_COMMENT, & new_comment); - if (c == END_FILE) - return lasttok = NEWLINE_EOF; + yylval = new_comment; + + if (c == END_FILE) { + pushback(); + return lasttok = NEWLINE; + } } else { while ((c = nextc(false)) != '\n') { if (c == END_FILE) @@ -3595,7 +3762,10 @@ retry: * Use it at your own risk. We think it's a bad idea, which * is why it's not on by default. */ + yylval = NULL; if (! do_traditional) { + INSTRUCTION *new_comment; + /* strip trailing white-space and/or comment */ while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') continue; @@ -3607,9 +3777,11 @@ retry: lintwarn( _("use of `\\ #...' line continuation is not portable")); } - if (do_pretty_print && ! do_profile) - c = get_comment(EOL_COMMENT); - else { + if (do_pretty_print && ! do_profile) { + c = get_comment(EOL_COMMENT, & new_comment); + yylval = new_comment; + return lasttok = c; + } else { while ((c = nextc(false)) != '\n') if (c == END_FILE) break; @@ -3630,11 +3802,20 @@ retry: } break; - case ':': case '?': + qm_col_count++; + // fall through + case ':': yylval = GET_INSTRUCTION(Op_cond_exp); - if (! do_posix) - allow_newline(); + if (qm_col_count > 0) { + if (! do_posix) { + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + } + if (c == ':') + qm_col_count--; + } return lasttok = c; /* @@ -4056,7 +4237,10 @@ retry: case '&': if ((c = nextc(true)) == '&') { yylval = GET_INSTRUCTION(Op_and); - allow_newline(); + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + return lasttok = LEX_AND; } pushback(); @@ -4066,11 +4250,15 @@ retry: case '|': if ((c = nextc(true)) == '|') { yylval = GET_INSTRUCTION(Op_or); - allow_newline(); + INSTRUCTION *new_comment = NULL; + allow_newline(& new_comment); + yylval->comment = new_comment; + return lasttok = LEX_OR; } else if (! do_traditional && c == '&') { yylval = GET_INSTRUCTION(Op_symbol); yylval->redir_type = redirect_twoway; + return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN); } pushback(); @@ -4118,18 +4306,39 @@ retry: while (c != END_FILE && is_identchar(c)) { tokadd(c); c = nextc(true); + + if (! do_traditional && c == ':') { + int peek = nextc(true); + + if (peek == ':') { // saw identifier:: + tokadd(c); + tokadd(c); + c = nextc(true); + } else + pushback(); + // then continue around the loop, c == ':' + } } tokadd('\0'); pushback(); + (void) validate_qualified_name(tokstart); + /* See if it is a special token. */ - if ((mid = check_special(tokstart)) >= 0) { + if ((mid = check_qualified_special(tokstart)) >= 0) { static int warntab[sizeof(tokentab) / sizeof(tokentab[0])]; int class = tokentab[mid].class; - if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL) - && lasttok != '@') - goto out; + switch (class) { + case LEX_EVAL: + case LEX_INCLUDE: + case LEX_LOAD: + case LEX_NAMESPACE: + if (lasttok != '@') + goto out; + default: + break; + } /* allow parameter names to shadow the names of gawk extension built-ins */ if ((tokentab[mid].flags & GAWKX) != 0) { @@ -4141,7 +4350,7 @@ retry: goto out; case FUNC_BODY: /* in body, name must be in symbol table for it to be a parameter */ - if ((f = lookup(tokstart)) != NULL) { + if ((f = lookup(tokstart, false)) != NULL) { if (f->type == Node_builtin_func) break; else @@ -4184,6 +4393,7 @@ retry: continue_allowed++; switch (class) { + case LEX_NAMESPACE: case LEX_INCLUDE: case LEX_LOAD: want_source = true; @@ -4203,7 +4413,7 @@ retry: case LEX_END: case LEX_BEGINFILE: case LEX_ENDFILE: - yylval = bcalloc(tokentab[mid].value, 3, sourceline); + yylval = bcalloc(tokentab[mid].value, 4, sourceline); break; case LEX_FOR: @@ -4260,8 +4470,11 @@ out: yylval->lextok = tokkey; #define SMART_ALECK 1 - if (SMART_ALECK && do_lint - && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { + if (SMART_ALECK + && do_lint + && ! goto_warned + && tolower(tokkey[0]) == 'g' + && strcasecmp(tokkey, "goto") == 0) { goto_warned = true; lintwarn(_("`goto' considered harmful!")); } @@ -4442,10 +4655,20 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) arg->nexti->opcode = Op_push_arg; /* argument may be array */ } - } else if (r->builtin == do_isarray || r->builtin == do_typeof) { + } else if (r->builtin == do_isarray) { + arg = subn->nexti; + if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) + arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ + } else if (r->builtin == do_typeof) { arg = subn->nexti; if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ + if (nexp == 2) { /* 2nd argument there */ + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } #ifdef SUPPLY_INTDIV } else if (r->builtin == do_intdiv #ifdef HAVE_MPFR @@ -4623,7 +4846,7 @@ parms_shadow(INSTRUCTION *pc, bool *shadow) * about all shadowed parameters. */ for (i = 0; i < pcount; i++) { - if (lookup(fp[i].param) != NULL) { + if (lookup(fp[i].param, false) != NULL) { warning( _("function `%s': parameter `%s' shadows global variable"), fname, fp[i].param); @@ -4734,13 +4957,15 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) /* 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; + if (interblock_comment != NULL) { + interblock_comment->source_line = 0; + merge_comments(interblock_comment, fi->comment); + fi->comment = interblock_comment; + interblock_comment = NULL; } - /* add an implicit return at end; + /* + * Add an implicit return at end; * also used by 'return' command in debugger */ @@ -4748,8 +4973,16 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) def->lasti->memory = dupnode(Nnull_string); (void) list_append(def, instruction(Op_K_return)); - if (do_pretty_print) + if (trailing_comment != NULL) { + (void) list_append(def, trailing_comment); + trailing_comment = NULL; + } + + if (do_pretty_print) { + fi[3].nexti = namespace_chain; + namespace_chain = NULL; (void) list_prepend(def, instruction(Op_exec_count)); + } /* fi->opcode = Op_func */ (fi + 1)->firsti = def->nexti; @@ -4781,7 +5014,7 @@ install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist) NODE *r, *f; int pcount = 0; - r = lookup(fname); + r = lookup(fname, true); if (r != NULL) { error_ln(fi->source_line, _("function name `%s' previously defined"), fname); return -1; @@ -4834,7 +5067,10 @@ check_params(char *fname, int pcount, INSTRUCTION *list) error_ln(p->source_line, _("function `%s': can't use special variable `%s' as a function parameter"), fname, name); - } + } else if (strchr(name, ':') != NULL) + error_ln(p->source_line, + _("function `%s': parameter `%s' cannot contain a namespace"), + fname, name); /* check for duplicate parameters */ for (j = 0; j < i; j++) { @@ -4922,22 +5158,19 @@ check_funcs() for (i = 0; i < HASHSIZE; i++) { for (fp = ftable[i]; fp != NULL; fp = fp->next) { -#ifdef REALLYMEAN - /* making this the default breaks old code. sigh. */ - if (fp->defined == 0 && ! fp->extension) { - error( - _("function `%s' called but never defined"), fp->name); - errcount++; - } -#else - if (do_lint && fp->defined == 0 && ! fp->extension) - lintwarn( - _("function `%s' called but never defined"), fp->name); -#endif + if (do_lint && ! fp->extension) { + /* + * Making this not a lint check and + * incrementing * errcount breaks old code. + * Sigh. + */ + if (fp->defined == 0) + lintwarn(_("function `%s' called but never defined"), + fp->name); - if (do_lint && fp->used == 0 && ! fp->extension) { - lintwarn(_("function `%s' defined but never called directly"), - fp->name); + if (fp->used == 0) + lintwarn(_("function `%s' defined but never called directly"), + fp->name); } } } @@ -4981,7 +5214,7 @@ variable(int location, char *name, NODETYPE type) { NODE *r; - if ((r = lookup(name)) != NULL) { + if ((r = lookup(name, true)) != NULL) { if (r->type == Node_func || r->type == Node_ext_func ) error_ln(location, _("function `%s' called with space between name and `(',\nor used as a variable or an array"), r->vname); @@ -5448,24 +5681,31 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) if (rule != Rule) { rp = pattern; - if (do_pretty_print) + if (do_pretty_print) { + rp[3].nexti = namespace_chain; + namespace_chain = NULL; (void) list_append(action, instruction(Op_no_op)); + } (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = action->lasti; (rp + 2)->first_line = pattern->source_line; (rp + 2)->last_line = lastline; - if (block_comment != NULL) { - ip = list_prepend(list_prepend(action, block_comment), rp); - block_comment = NULL; - } else - ip = list_prepend(action, rp); - + ip = list_prepend(action, rp); + if (interblock_comment != NULL) { + ip = list_prepend(ip, interblock_comment); + interblock_comment = NULL; + } } else { - rp = bcalloc(Op_rule, 3, 0); + rp = bcalloc(Op_rule, 4, 0); rp->in_rule = Rule; rp->source_file = source; tp = instruction(Op_no_op); + if (do_pretty_print) { + rp[3].nexti = namespace_chain; + namespace_chain = NULL; + } + if (pattern == NULL) { /* assert(action != NULL); */ if (do_pretty_print) @@ -5485,14 +5725,20 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) (rp + 2)->last_line = find_line(pattern, LAST_LINE); action = list_create(instruction(Op_K_print_rec)); if (do_pretty_print) - (void) list_prepend(action, instruction(Op_exec_count)); + action = list_prepend(action, instruction(Op_exec_count)); } else (rp + 2)->last_line = lastline; + if (interblock_comment != NULL) { // was after previous action + pattern = list_prepend(pattern, interblock_comment); + interblock_comment = NULL; + } + if (do_pretty_print) { - (void) list_prepend(pattern, instruction(Op_exec_count)); - (void) list_prepend(action, instruction(Op_exec_count)); + pattern = list_prepend(pattern, instruction(Op_exec_count)); + action = list_prepend(action, instruction(Op_exec_count)); } + (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = tp; ip = list_append( @@ -5864,8 +6110,9 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, forp->target_break = tbreak; forp->target_continue = tcont; ret = list_prepend(ret, forp); - } /* else - forp is NULL */ + } + /* else + forp is NULL */ return ret; } @@ -6079,26 +6326,6 @@ list_merge(INSTRUCTION *l1, INSTRUCTION *l2) return l1; } -/* add_pending_comment --- add a pending comment to a statement */ - -static inline INSTRUCTION * -add_pending_comment(INSTRUCTION *stmt) -{ - INSTRUCTION *ret = stmt; - - if (prior_comment != NULL) { - if (function_comment != prior_comment) - ret = list_append(stmt, prior_comment); - prior_comment = NULL; - } else if (comment != NULL && comment->memory->comment_type == EOL_COMMENT) { - if (function_comment != comment) - ret = list_append(stmt, comment); - comment = NULL; - } - - return ret; -} - /* See if name is a special token. */ int @@ -6196,6 +6423,9 @@ one_line_close(int fd) builtin_func_t lookup_builtin(const char *name) { + if (strncmp(name, "awk::", 5) == 0) + name += 5; + int mid = check_special(name); if (mid == -1) @@ -6267,9 +6497,6 @@ install_builtins(void) bool is_alpha(int c) { -#ifdef I_DONT_KNOW_WHAT_IM_DOING - return isalpha(c); -#else /* ! I_DONT_KNOW_WHAT_IM_DOING */ switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': @@ -6284,7 +6511,6 @@ is_alpha(int c) return true; } return false; -#endif /* ! I_DONT_KNOW_WHAT_IM_DOING */ } /* is_alnum --- return true for alphanumeric, English only letters */ @@ -6342,3 +6568,258 @@ set_profile_text(NODE *n, const char *str, size_t len) return n; } + +/* + * merge_comments --- merge c2 into c1 and free c2 if successful. + * Allow c2 to be NULL, in which case just merged chained + * comments in c1. + */ + +static void +merge_comments(INSTRUCTION *c1, INSTRUCTION *c2) +{ + assert(c1->opcode == Op_comment); + + if (c1->comment == NULL && c2 == NULL) // nothing to do + return; + + size_t total = c1->memory->stlen; + if (c1->comment != NULL) + total += 1 /* \n */ + c1->comment->memory->stlen; + + if (c2 != NULL) { + assert(c2->opcode == Op_comment); + total += 1 /* \n */ + c2->memory->stlen; + if (c2->comment != NULL) + total += c2->comment->memory->stlen + 1; + } + + char *buffer; + emalloc(buffer, char *, total + 1, "merge_comments"); + + strcpy(buffer, c1->memory->stptr); + if (c1->comment != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c1->comment->memory->stptr); + } + + if (c2 != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c2->memory->stptr); + if (c2->comment != NULL) { + strcat(buffer, "\n"); + strcat(buffer, c2->comment->memory->stptr); + } + + unref(c2->memory); + if (c2->comment != NULL) { + unref(c2->comment->memory); + bcfree(c2->comment); + c2->comment = NULL; + } + bcfree(c2); + } + + c1->memory->comment_type = BLOCK_COMMENT; + free(c1->memory->stptr); + c1->memory->stptr = buffer; + c1->memory->stlen = strlen(buffer); + + // now free everything else + if (c1->comment != NULL) { + unref(c1->comment->memory); + bcfree(c1->comment); + c1->comment = NULL; + } +} + +/* make_braced_statements --- handle `l_brace statements r_brace' with comments */ + +static INSTRUCTION * +make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace) +{ + INSTRUCTION *ip; + + if (stmts == NULL) + ip = list_create(instruction(Op_no_op)); + else + ip = stmts; + + if (lbrace != NULL) { + INSTRUCTION *comment2 = lbrace->comment; + if (comment2 != NULL) { + ip = list_prepend(ip, comment2); + lbrace->comment = NULL; + } + ip = list_prepend(ip, lbrace); + } + + return ip; +} + +/* validate_qualified_name --- make sure that a qualified name is built correctly */ + +/* + * This routine returns upon first error, no need to produce multiple, possibly + * conflicting / confusing error messages. + */ + +bool +validate_qualified_name(char *token) +{ + char *cp, *cp2; + + // no colon, by definition it's well formed + if ((cp = strchr(token, ':')) == NULL) + return true; + + if (do_traditional || do_posix) { + error_ln(sourceline, _("identifier %s: qualified names not allowed in traditional / POSIX mode"), token); + return false; + } + + if (cp[1] != ':') { // could happen from command line + error_ln(sourceline, _("identifier %s: namespace separator is two colons, not one"), token); + return false; + } + + if (! is_letter(cp[2])) { + error_ln(sourceline, + _("qualified identifier `%s' is badly formed"), + token); + return false; + } + + if ((cp2 = strchr(cp+2, ':')) != NULL) { + error_ln(sourceline, + _("identifier `%s': namespace separator can only appear once in a qualified name"), + token); + return false; + } + + return true; +} + +/* check_qualified_special --- decide if a name is special or not */ + +static int +check_qualified_special(char *token) +{ + char *cp; + + if ((cp = strchr(token, ':')) == NULL && current_namespace == awk_namespace) + return check_special(token); + + /* + * Now it's more complicated. Here are the rules. + * + * 1. Namespace name cannot be a standard awk reserved word or function. + * 2. Subordinate part of the name cannot be standard awk reserved word or function. + * 3. If namespace part is explicitly "awk", return result of check_special(). + * 4. Else return -1 (gawk extensions allowed, we check standard awk in step 2). + */ + + const struct token *tok; + int i; + if (cp == NULL) { // namespace not awk, but a simple identifier + i = check_special(token); + if (i < 0) + return i; + + tok = & tokentab[i]; + if ((tok->flags & GAWKX) != 0 && tok->class == LEX_BUILTIN) + return -1; + else + return i; + } + + char *ns, *end, *subname; + ns = token; + *(end = cp) = '\0'; // temporarily turn it into standalone string + subname = end + 2; + + // First check the namespace part + i = check_special(ns); + if (i >= 0 && (tokentab[i].flags & GAWKX) == 0) { + error_ln(sourceline, _("using reserved identifier `%s' as a namespace is not allowed"), ns); + goto done; + } + + // Now check the subordinate part + i = check_special(subname); + if (i >= 0 && (tokentab[i].flags & GAWKX) == 0 && strcmp(ns, "awk") != 0) { + error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname); + goto done; + } + + if (strcmp(ns, "awk") == 0) { + i = check_special(subname); + if (i >= 0) { + if ((tokentab[i].flags & GAWKX) != 0 && tokentab[i].class == LEX_BUILTIN) + ; // gawk additional builtin function, is ok + else + error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname); + } + } else + i = -1; +done: + *end = ':'; + return i; +} + +/* set_namespace --- change the current namespace */ + +static void +set_namespace(INSTRUCTION *ns, INSTRUCTION *comment) +{ + if (ns == NULL) + return; + + if (do_traditional || do_posix) { + error_ln(ns->source_line, _("@namespace is a gawk extension")); + efree(ns->lextok); + bcfree(ns); + return; + } + + if (! is_valid_identifier(ns->lextok)) { + error_ln(ns->source_line, _("namespace name `%s' must meet identifier naming rules"), ns->lextok); + efree(ns->lextok); + bcfree(ns); + return; + } + + int mid = check_special(ns->lextok); + + if (mid >= 0) { + error_ln(ns->source_line, _("using reserved identifier `%s' as a namespace is not allowed"), ns->lextok); + efree(ns->lextok); + bcfree(ns); + return; + } + + if (strcmp(ns->lextok, current_namespace) == 0) + efree(ns->lextok); + else if (strcmp(ns->lextok, awk_namespace) == 0) { + efree(ns->lextok); + current_namespace = awk_namespace; + } else { + if (current_namespace != awk_namespace) + efree((char *) current_namespace); + current_namespace = ns->lextok; + } + + // save info and push on front of list of namespaces seen + INSTRUCTION *new_ns = instruction(Op_K_namespace); + new_ns->comment = comment; + new_ns->ns_name = estrdup(current_namespace, strlen(current_namespace)); + new_ns->nexti = namespace_chain; + namespace_chain = new_ns; + + ns->lextok = NULL; + bcfree(ns); + + namespace_changed = true; + + return; +} diff --git a/awklib/eg/lib/inplace.awk b/awklib/eg/lib/inplace.awk index 6771bc45..68dad92e 100644 --- a/awklib/eg/lib/inplace.awk +++ b/awklib/eg/lib/inplace.awk @@ -21,11 +21,15 @@ # # Andrew J. Schorr, aschorr@telemetry-investments.com # January 2013 +# +# Revised for namespaces +# Arnold Robbins, arnold@skeeve.com +# July 2017 @load "inplace" -# Please set INPLACE_SUFFIX to make a backup copy. For example, you may -# want to set INPLACE_SUFFIX to .bak on the command line or in a BEGIN rule. +# Please set inplace::suffix to make a backup copy. For example, you may +# want to set inplace::suffix to .bak on the command line or in a BEGIN rule. # By default, each filename on the command line will be edited inplace. # But you can selectively disable this by adding an inplace=0 argument @@ -33,23 +37,25 @@ # reenable it later on the commandline by putting inplace=1 before files # that you wish to be subject to inplace editing. -# N.B. We call inplace_end() in the BEGINFILE and END rules so that any +# N.B. We call inplace::end() in the BEGINFILE and END rules so that any # actions in an ENDFILE rule will be redirected as expected. +@namespace "inplace" + BEGIN { - inplace = 1 # enabled by default + enable = 1 # enabled by default } BEGINFILE { - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) - if (inplace) - inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) + if (enable) + begin(filename = FILENAME, suffix) else - _inplace_filename = "" + filename = "" } END { - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) } diff --git a/awklib/eg/lib/ns_passwd.awk b/awklib/eg/lib/ns_passwd.awk new file mode 100644 index 00000000..b9b6bce5 --- /dev/null +++ b/awklib/eg/lib/ns_passwd.awk @@ -0,0 +1,72 @@ +# ns_passwd.awk --- access password file information +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 +# +# Reworked for namespaces June 2017, with help from +# Andrew J.: Schorr, aschorr@telemetry-investments.com + +@namespace "passwd" + +BEGIN { + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" +} + +function Init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +{ + if (Inited) + return + + oldfs = FS + oldrs = RS + olddol0 = $0 + using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (PROCINFO["FS"] == "FPAT") + FS = ":" + RS = "\n" + + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) { + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + } + close(pwcat) + Count = 0 + Inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +} + +function awk::getpwnam(name) +{ + Init() + return Byname[name] +} + +function awk::getpwuid(uid) +{ + Init() + return Byuid[uid] +} + +function awk::getpwent() +{ + Init() + if (Count < Total) + return Bycount[++Count] + return "" +} + +function awk::endpwent() +{ + Count = 0 +} @@ -4071,13 +4071,31 @@ do_typeof(int nargs) NODE *arg; char *res = NULL; bool deref = true; + NODE *dbg; + if (nargs == 2) { /* 2nd optional arg for debugging */ + dbg = POP_PARAM(); + if (dbg->type != Node_var_array) + fatal(_("typeof: second argument is not an array")); + assoc_clear(dbg); + } + else + dbg = NULL; arg = POP(); switch (arg->type) { case Node_var_array: /* Node_var_array is never UPREF'ed */ res = "array"; deref = false; + if (dbg) { + NODE *sub = make_string("array_type", 10); + NODE **lhs = assoc_lookup(dbg, sub); + unref(*lhs); + *lhs = make_string(arg->array_funcs->name, strlen(arg->array_funcs->name)); + if (dbg->astore != NULL) + (*dbg->astore)(dbg, sub); + unref(sub); + } break; case Node_val: switch (fixtype(arg)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) { @@ -4106,6 +4124,16 @@ do_typeof(int nargs) } break; } + if (dbg) { + const char *s = flags2str(arg->flags); + NODE *sub = make_string("flags", 5); + NODE **lhs = assoc_lookup(dbg, sub); + unref(*lhs); + *lhs = make_string(s, strlen(s)); + if (dbg->astore != NULL) + (*dbg->astore)(dbg, sub); + unref(sub); + } break; case Node_var_new: res = "untyped"; diff --git a/cint_array.c b/cint_array.c index 05b94400..497bd792 100644 --- a/cint_array.c +++ b/cint_array.c @@ -59,10 +59,10 @@ static NODE **cint_dump(NODE *symbol, NODE *ndump); static void cint_print(NODE *symbol); #endif -afunc_t cint_array_func[] = { +const array_funcs_t cint_array_func = { + "cint", cint_array_init, is_uinteger, - null_length, cint_lookup, cint_exists, cint_clear, @@ -256,9 +256,9 @@ xinstall: */ if (is_integer(xn, subs)) - xn->array_funcs = int_array_func; + xn->array_funcs = & int_array_func; else - xn->array_funcs = str_array_func; + xn->array_funcs = & str_array_func; xn->flags |= XARRAY; } return xn->alookup(xn, subs); @@ -526,7 +526,7 @@ cint_dump(NODE *symbol, NODE *ndump) kb += (INT32_BIT * sizeof(NODE *)) / 1024.0; /* symbol->nodes */ kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0; /* value nodes in Node_array_leaf(s) */ if (xn != NULL) { - if (xn->array_funcs == int_array_func) + if (xn->array_funcs == & int_array_func) kb += int_kilobytes(xn); else kb += str_kilobytes(xn); @@ -1954,7 +1954,7 @@ yyreduce: #line 472 "command.y" /* yacc.c:1645 */ { NODE *n; - n = lookup((yyvsp[0])->a_string); + n = lookup((yyvsp[0])->a_string, true); if (n == NULL || n->type != Node_func) yyerror(_("no such function - \"%s\""), (yyvsp[0])->a_string); else { @@ -471,7 +471,7 @@ func_name : D_STRING { NODE *n; - n = lookup($1->a_string); + n = lookup($1->a_string, true); if (n == NULL || n->type != Node_func) yyerror(_("no such function - \"%s\""), $1->a_string); else { @@ -108,9 +108,6 @@ /* Define if you have the libsigsegv library. */ #undef HAVE_LIBSIGSEGV -/* Define to 1 if you have the <limits.h> header file. */ -#undef HAVE_LIMITS_H - /* Define to 1 if you have the <locale.h> header file. */ #undef HAVE_LOCALE_H @@ -186,9 +183,6 @@ /* we have sockets on this system */ #undef HAVE_SOCKETS -/* Define to 1 if you have the <stdarg.h> header file. */ -#undef HAVE_STDARG_H - /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H @@ -344,9 +338,6 @@ /* Define to 1 if you have the `__etoa_l' function. */ #undef HAVE___ETOA_L -/* enable severe portability problems */ -#undef I_DONT_KNOW_WHAT_IM_DOING - /* disable lint checks */ #undef NO_LINT @@ -401,9 +392,6 @@ /* Define to 1 if the character set is EBCDIC */ #undef USE_EBCDIC -/* force use of our version of strftime */ -#undef USE_INCLUDED_STRFTIME - /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for GNU Awk 4.2.1a. +# Generated by GNU Autoconf 2.69 for GNU Awk 4.2.60. # # Report bugs to <bug-gawk@gnu.org>. # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='GNU Awk' PACKAGE_TARNAME='gawk' -PACKAGE_VERSION='4.2.1a' -PACKAGE_STRING='GNU Awk 4.2.1a' +PACKAGE_VERSION='4.2.60' +PACKAGE_STRING='GNU Awk 4.2.60' PACKAGE_BUGREPORT='bug-gawk@gnu.org' PACKAGE_URL='http://www.gnu.org/software/gawk/' @@ -763,9 +763,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules -with_whiny_user_strftime enable_lint -enable_severe_portability_problems enable_builtin_intdiv0 enable_mpfr enable_versioned_extension_dir @@ -1332,7 +1330,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures GNU Awk 4.2.1a to adapt to many kinds of systems. +\`configure' configures GNU Awk 4.2.60 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1402,7 +1400,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of GNU Awk 4.2.1a:";; + short | recursive ) echo "Configuration of GNU Awk 4.2.60:";; esac cat <<\_ACEOF @@ -1413,8 +1411,6 @@ 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 do not compile in gawk lint checking - --enable-severe-portability-problems - allow really nasty portability problems --enable-builtin-intdiv0 enable built-in intdiv0 function --disable-mpfr do not check for MPFR @@ -1432,9 +1428,6 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-whiny-user-strftime - force use of included version of strftime for - deficient systems --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib --without-libiconv-prefix don't search for libiconv in includedir and libdir @@ -1529,7 +1522,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -GNU Awk configure 4.2.1a +GNU Awk configure 4.2.60 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2238,7 +2231,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by GNU Awk $as_me 4.2.1a, which was +It was created by GNU Awk $as_me 4.2.60, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3121,7 +3114,7 @@ fi # Define the identity of the package. PACKAGE='gawk' - VERSION='4.2.1a' + VERSION='4.2.60' cat >>confdefs.h <<_ACEOF @@ -3217,18 +3210,6 @@ fi - -# Check whether --with-whiny-user-strftime was given. -if test "${with_whiny_user_strftime+set}" = set; then : - withval=$with_whiny_user_strftime; if test "$withval" = yes - then - -$as_echo "#define USE_INCLUDED_STRFTIME 1" >>confdefs.h - - fi - -fi - # Check whether --enable-lint was given. if test "${enable_lint+set}" = set; then : enableval=$enable_lint; if test "$enableval" = no @@ -3240,17 +3221,6 @@ $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 - # Check whether --enable-builtin-intdiv0 was given. if test "${enable_builtin_intdiv0+set}" = set; then : enableval=$enable_builtin_intdiv0; if test "$enableval" = yes @@ -8063,8 +8033,8 @@ $as_echo "#define HAVE_LC_MESSAGES 1" >>confdefs.h fi -for ac_header in arpa/inet.h fcntl.h limits.h locale.h libintl.h mcheck.h \ - netdb.h netinet/in.h stdarg.h stddef.h string.h \ +for ac_header in arpa/inet.h fcntl.h locale.h libintl.h mcheck.h \ + netdb.h netinet/in.h stddef.h string.h \ sys/ioctl.h sys/param.h sys/select.h sys/socket.h sys/time.h unistd.h \ termios.h stropts.h wchar.h wctype.h do : @@ -11630,7 +11600,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by GNU Awk $as_me 4.2.1a, which was +This file was extended by GNU Awk $as_me 4.2.60, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -11698,7 +11668,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -GNU Awk config.status 4.2.1a +GNU Awk config.status 4.2.60 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 801bf839..9e11f8ca 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl dnl Process this file with autoconf to produce a configure script. -AC_INIT([GNU Awk],[4.2.1a],[bug-gawk@gnu.org],[gawk]) +AC_INIT([GNU Awk],[4.2.60],[bug-gawk@gnu.org],[gawk]) # This is a hack. Different versions of install on different systems # are just too different. Chuck it and use install-sh. @@ -44,15 +44,6 @@ AM_INIT_AUTOMAKE([1.15 dist-xz dist-lzip]) AC_CONFIG_MACRO_DIR([m4]) -dnl Additional argument stuff -AC_ARG_WITH(whiny-user-strftime, - [AS_HELP_STRING([--with-whiny-user-strftime], [force use of included version of strftime for deficient systems])], - if test "$withval" = yes - then - AC_DEFINE(USE_INCLUDED_STRFTIME, 1, - [force use of our version of strftime]) - fi -) AC_ARG_ENABLE([lint], [AS_HELP_STRING([--disable-lint],[do not compile in gawk lint checking])], if test "$enableval" = no @@ -60,13 +51,6 @@ AC_ARG_ENABLE([lint], AC_DEFINE(NO_LINT, 1, [disable lint checks]) fi ) -AC_ARG_ENABLE([severe-portability-problems], - [AS_HELP_STRING([--enable-severe-portability-problems],[allow really nasty portability problems])], - if test "$enableval" = yes - then - AC_DEFINE(I_DONT_KNOW_WHAT_IM_DOING, 1, [enable severe portability problems]) - fi -) AC_ARG_ENABLE([builtin-intdiv0], [AS_HELP_STRING([--enable-builtin-intdiv0],[enable built-in intdiv0 function])], if test "$enableval" = yes @@ -172,8 +156,8 @@ AM_LANGINFO_CODESET gt_LC_MESSAGES dnl checks for header files -AC_CHECK_HEADERS(arpa/inet.h fcntl.h limits.h locale.h libintl.h mcheck.h \ - netdb.h netinet/in.h stdarg.h stddef.h string.h \ +AC_CHECK_HEADERS(arpa/inet.h fcntl.h locale.h libintl.h mcheck.h \ + netdb.h netinet/in.h stddef.h string.h \ sys/ioctl.h sys/param.h sys/select.h sys/socket.h sys/time.h unistd.h \ termios.h stropts.h wchar.h wctype.h) AC_HEADER_STDC @@ -70,11 +70,6 @@ #define HAVE_MKTIME 1 #endif -/* For whiny users */ -#ifdef USE_INCLUDED_STRFTIME -#undef HAVE_STRFTIME -#endif - /* For HP/UX with gcc */ #if defined(hpux) || defined(_HPUX_SOURCE) #undef HAVE_TZSET @@ -310,6 +310,7 @@ static void delete_item(struct list_item *d); static int breakpoint_triggered(BREAKPOINT *b); static int watchpoint_triggered(struct list_item *w); static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump); +static void print_ns_list(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump); static int print_code(INSTRUCTION *pc, void *x); static void next_command(); static void debug_post_execute(INSTRUCTION *pc); @@ -1031,7 +1032,7 @@ NODE *find_symbol(const char *name, char **pname) if (prog_running) r = find_param(name, cur_frame, pname); if (r == NULL) - r = lookup(name); + r = lookup(name, false); // for now, require fully qualified name if (r == NULL) fprintf(out_fp, _("no symbol `%s' in current context\n"), name); return r; @@ -3807,7 +3808,12 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_K_do: - print_func(fp, "[doloop_cond = %p] [target_break = %p]\n", (pc+1)->doloop_cond, pc->target_break); + print_func(fp, "[doloop_cond = %p] [target_break = %p]", (pc+1)->doloop_cond, pc->target_break); + if (pc->comment) + print_func(fp, " [comment = %p]", pc->comment); + print_func(fp, "\n"); + if (pc->comment) + print_instruction(pc->comment, print_func, fp, in_dump); break; case Op_K_for: @@ -3815,15 +3821,44 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) /* fall through */ case Op_K_arrayfor: print_func(fp, "[forloop_body = %p] ", (pc+1)->forloop_body); - print_func(fp, "[target_break = %p] [target_continue = %p]\n", pc->target_break, pc->target_continue); + print_func(fp, "[target_break = %p] [target_continue = %p]", pc->target_break, pc->target_continue); + if (pc->comment != NULL) { + print_func(fp, " [comment = %p]\n", (pc)->comment); + print_instruction(pc->comment, print_func, fp, in_dump); + } else + print_func(fp, "\n"); break; case Op_K_switch: + { + bool need_newline = false; print_func(fp, "[switch_start = %p] [switch_end = %p]\n", (pc+1)->switch_start, (pc+1)->switch_end); + if (pc->comment || (pc+1)->switch_end->comment) + print_func(fp, "%*s", noffset, ""); + if (pc->comment) { + print_func(fp, "[start_comment = %p]", pc->comment); + need_newline = true; + } + if ((pc+1)->switch_end->comment) { + print_func(fp, "[end_comment = %p]", (pc + 1)->switch_end->comment); + need_newline = true; + } + if (need_newline) + print_func(fp, "\n"); + if (pc->comment) + print_instruction(pc->comment, print_func, fp, in_dump); + if ((pc+1)->switch_end->comment) + print_instruction((pc+1)->switch_end->comment, print_func, fp, in_dump); + } break; case Op_K_default: - print_func(fp, "[stmt_start = %p] [stmt_end = %p]\n", pc->stmt_start, pc->stmt_end); + print_func(fp, "[stmt_start = %p] [stmt_end = %p]", pc->stmt_start, pc->stmt_end); + if (pc->comment) { + print_func(fp, " [comment = %p]\n", pc->comment); + print_instruction(pc->comment, print_func, fp, in_dump); + } else + print_func(fp, "\n"); break; case Op_var_update: @@ -3848,8 +3883,13 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_func: - print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount, + print_func(fp, "[param_cnt = %d] [source_file = %s]", pcount, pc->source_file ? pc->source_file : "cmd. line"); + if (pc[3].nexti != NULL) { + print_func(fp, "[ns_list = %p]\n", pc[3].nexti); + print_ns_list(pc[3].nexti, print_func, fp, in_dump); + } else + print_func(fp, "\n"); break; case Op_K_getline_redir: @@ -3915,8 +3955,22 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_K_case: - print_func(fp, "[target_jmp = %p] [match_exp = %s]\n", + print_func(fp, "[target_jmp = %p] [match_exp = %s]", pc->target_jmp, (pc + 1)->match_exp ? "true" : "false"); + if (pc->comment) { + print_func(fp, " [comment = %p]\n", pc->comment); + print_instruction(pc->comment, print_func, fp, in_dump); + } else + print_func(fp, "\n"); + break; + + case Op_K_namespace: + print_func(fp, "[namespace = %s]", pc->ns_name); + if (pc->nexti) + print_func(fp, "[nexti = %p]", pc->nexti); + if (pc->comment) + print_func(fp, "[comment = %p]", pc->comment); + print_func(fp, "\n"); break; case Op_arrayfor_incr: @@ -3957,7 +4011,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_builtin: - print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin), + print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin, false), pc->expr_count); break; @@ -3995,9 +4049,14 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) break; case Op_rule: - print_func(fp, "[in_rule = %s] [source_file = %s]\n", + print_func(fp, "[in_rule = %s] [source_file = %s]", ruletab[pc->in_rule], pc->source_file ? pc->source_file : "cmd. line"); + if (pc[3].nexti != NULL) { + print_func(fp, "[ns_list = %p]\n", pc[3].nexti); + print_ns_list(pc[3].nexti, print_func, fp, in_dump); + } else + print_func(fp, "\n"); break; case Op_lint: @@ -4032,9 +4091,14 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) case Op_comment: print_memory(pc->memory, func, print_func, fp); - print_func(fp, " [comment_type = %s]\n", + print_func(fp, " [comment_type = %s]", pc->memory->comment_type == EOL_COMMENT ? - "EOL" : "FULL"); + "EOL" : "BLOCK"); + if (pc->comment) { + print_func(fp, " [comment = %p]\n", pc->comment); + print_instruction(pc->comment, print_func, fp, in_dump); + } else + print_func(fp, "\n"); break; case Op_push_i: @@ -4086,6 +4150,18 @@ print_code(INSTRUCTION *pc, void *x) return 0; } +/* print_ns_list --- print the list of namespaces */ + +static void +print_ns_list(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) +{ + for (; pc != NULL; pc = pc->nexti) { + print_instruction(pc, print_func, fp, in_dump); + if (pc->comment != NULL) + print_instruction(pc->comment, print_func, fp, in_dump); + } +} + /* do_dump_instructions --- dump command */ int @@ -5530,7 +5606,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) return false; } - f = lookup("@eval"); + f = lookup("@eval", false); assert(f != NULL); if (this_func == NULL) { /* in main */ /* do a function call */ diff --git a/doc/ChangeLog b/doc/ChangeLog index 1c740385..878e3982 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -12,6 +12,10 @@ * gawktexi.in (I18N Example): $LC_MESSAGES is involved here also. Document this. +2019-01-09 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawktexi.in (Undocumented): Discuss typeof's optional 2nd argument. + 2019-01-08 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in (I18N Example): Add more explanation of how to @@ -26,6 +30,37 @@ * gawktexi.in: Some small indexing fixes. Thanks to Antonio Giovanni Colombo for pointing them out. +2019-01-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: A few more fixes w.r.t. namespaces. Thanks to + Antonio Giovanni Colombo for pointing out the problems. + +2018-12-31 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: A few fixes w.r.t. namespaces. Thanks to + Antonio Giovanni Colombo for pointing out the problems. + +2018-12-18 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Added more indexing to the debugger chapter. + Add more indexing to namespaces chapter, too. + +2018-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Clean up some FIXMEs and other improvements. + * gawk.1: Mention that files read with -f and -i and command + line segments all implicitly start with @namespace "awk". + +2018-12-18 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Added more indexing to the debugger chapter. + +2018-11-29 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Auto-set): Document that you can no longer use + arbitrary indices in SYMTAB. + * gawk.1: Ditto. + 2018-12-18 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Added more indexing to the debugger chapter. @@ -37,6 +72,12 @@ 2018-11-26 Arnold D. Robbins <arnold@skeeve.com> + * gawktexi.in (Auto-set) : Update values of PROCINFO["platform"]. + (PC Using): Add to BINMODE discussion to always set it and + not worry about checking platforms. Per discussion with the dev team. + +2018-11-26 Arnold D. Robbins <arnold@skeeve.com> + * gawktexi.in: Document that split() third arg is like FS, if it's a single character, that character is used, even if it's a regexp metacharacter. @@ -45,6 +86,11 @@ 2018-11-25 Arnold D. Robbins <arnold@skeeve.com> + * gawktexi.in: Document PROCINFO["platform"]. + * gawk.1: Ditto. + +2018-11-25 Arnold D. Robbins <arnold@skeeve.com> + * gawktexi.in: Small typo fix. 2018-11-24 Arnold D. Robbins <arnold@skeeve.com> @@ -57,6 +103,10 @@ * gawktexi.in): Small typo fixes. Thanks to Antonio Giovanni Colombo for pointing them out. +2018-11-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Profiling): Review and update. + 2018-10-30 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in (Arrays of Arrays): Typo fix in code. Thanks to Alto Tom @@ -74,6 +124,12 @@ Communications Guidelines, with URL. * texinfo.tex: Updated from GNULIB. +2018-10-17 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Profiling): Revise example for pattern without + action and note that the profiler distinguishes `print' and + `print $0'. + 2018-09-23 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in (Extracting): Note that patch levels above @@ -377,13 +433,27 @@ * gawkexti.in: Remove sentence indicating that isarray is deprecated and recommending typeof instead. +2017-10-16 Arnold D. Robbins <arnold@skeeve.com> + + * awkcard.in: Add @namespaces to Execution section. + +2017-10-12 Arnold D. Robbins <arnold@skeeve.com> + + * gawk.1: Documents namespaces. + * awkcard.in: Ditto. + 2017-10-10 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in (Readfile Function): Fix the code for the naive function to be syntactically and semantically correct. Thanks to Jaromir Obr <jaromir.obr@gmail.com> for the report. (POSIX String Comparison): Add some URL references in @ignore. - + + Unrelated: + + * gawktexi.in: Remove description of --with-whiny-user-strftime + configuration option. + 2017-10-08 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawktexi.in: Fix discussion of AWKPATH in section on @include. @@ -480,6 +550,11 @@ * texinfo.tex: Updated. +2017-08-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespace Summary): Add summary to namespace + chapter. + 2017-08-01 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Update with info about DJGPP port now @@ -489,6 +564,8 @@ * gawktexi.in (Type Functions): Improve the example for untyped variables. + (Extension Exercises): Remove the exercise that talks + about namespaces, since it's no longer relevant. 2017-07-28 Arnold D. Robbins <arnold@skeeve.com> @@ -496,15 +573,60 @@ inplace.awk; should have done that when it was first added. Oops. +2017-07-26 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): More edits. + 2017-07-21 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Fix a spelling error. * wordlist: Update with more words. + Done also for namespace material. + +2017-07-20 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Extension Sample Inplace): Rework to use the + "inplace" namespace. + + * gawktexi.in (Namespace And Features): Renamed from + `Namespace Misc' and reworked. + (Symbol table by name): Add note about namespace and + component name rules with xref to section in Namespaces chapter. + +2017-07-19 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Cleanup, new section on naming rules + added. + +2017-07-17 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Revised password suite example. + (Symbol table by name): Add entries for namespace versions + of lookup and update routines. + +2017-07-13 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): More updates. Especially that + reserved words are not allowed in either half of a fully + qualified name or as a namespace. + +2017-07-05 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): More updates. + 2017-07-02 Arnold D. Robbins <arnold@skeeve.com> * texinfo.tex: Pull in latest from Texinfo SVN. +2017-06-30 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Move to later in the book. + +2017-06-23 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): More minor doc edits. + 2017-06-19 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawktexi.in (Memory Allocation Functions and Convenience Macros): @@ -517,11 +639,42 @@ 2017-06-15 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Expand tab characters. + * gawktexi.in (Namespaces): Further minor doc edits, including + hyphenation hint. + +2017-06-13 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Document that reserved words and + predefined functions can be namespace names but can be in + the second part of a fully qualified name. (Design decision + change.) + +2017-06-11 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Document that reserved words and + predefined functions can't be namespace names. Reformat the + input a little bit. + +2017-06-06 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Further clarifications. Move to + `::' as the namespace separator. 2017-06-05 Andrew J. Schorr <aschorr@telemetry-investments.com> * gawktexi.in (Checking for MPFR): Fix typo. +2017-06-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in (Namespaces): Fixes in passwd.awk example. Document + that indirect calls with an unadorned name assume "awk" namespace. + +2017-05-30 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Initial doc on namespaces. Serves as a design + right now. + * gawktexi.in: More doc added. + 2017-05-30 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Document PROCINFO["argv"]. diff --git a/doc/awkcard.in b/doc/awkcard.in index d4df3427..1a6b72f5 100644 --- a/doc/awkcard.in +++ b/doc/awkcard.in @@ -47,7 +47,8 @@ .ES .in +.2i .nf -\*(FRAction Statements 9 +\*(FRAcknowledgements 9 +Action Statements 9 Arrays 7 Awk Program Execution 5 Bit Manipulation Functions (\*(GK) 17 @@ -70,6 +71,7 @@ Input Control 13 Internationalization (\*(GK) 18 Lines And Statements 4 Localization (\*(GK) 12 +Namespaces 12 Numeric Functions 15 Output Control 13 Pattern Elements 8 @@ -88,9 +90,6 @@ Variables 5\*(CX .sp .4 .TD .fi -\*(CD\*(FRArnold Robbins wrote this reference card. -We thank -Brian Kernighan and Michael Brennan who reviewed it. .sp .4 .SL .sp .4 @@ -446,7 +445,9 @@ and optional function definitions. .sp .5 \*(CB\*(FC@include "\*(FIfilename\*(FC" .br - \*(FC@load "\*(FIfilename\*(FC"\*(CD + \*(FC@load "\*(FIfilename\*(FC" +.br + \*(FC@namespace "\*(FInamespace\*(FC"\*(CD .br \*(FIpattern\*(FC { \*(FIaction statements\*(FC }\*(FR .br @@ -523,7 +524,7 @@ T} \*(CL\*(FCBINMODE\fP T{ Controls ``binary'' mode for all file I/O. Values of 1, 2, or 3, indicate input, output, or all files, respectively, should use binary -I/O. \*(CR(Not \*(NK.) \*(CLApplies only to non-POSIX systems. +I/O. \*(CR(Not \*(NK.) \*(CLOnly for non-POSIX systems. \*(CBFor \*(GK, string values of \*(FC"r"\fP, or \*(FC"w"\fP specify that input files, or output files, respectively, should use binary I/O. Use \*(FC"rw"\fP or \*(FC"wr"\fP for all files.\*(CX @@ -967,6 +968,14 @@ lp8 lp8 lp8 lp8. \*(FC\e"\fP~double quote~\*(FC\e/\fP~forward slash\*(CX .TE .EB "\s+2\f(HBESCAPE SEQUENCES\*(FR\s0" +.sp +.\" --- Acknowledgements +.ES +.fi +\*(CD\*(FRArnold Robbins wrote this reference card. +We thank +Brian Kernighan and Michael Brennan who reviewed it.\*(CX +.EB "\s+2\f(HBACKNOWLEDGMENTS\*(FR\s0" .BT .\" --- Records @@ -1276,6 +1285,26 @@ Usable only with the \*(FC|&\*(FR two-way I/O operator. Similar, but use UDP/IP instead of TCP/IP.\*(CL .in -.2i .EB "\s+2\f(HBSPECIAL FILENAMES\*(FR\s0" +.sp .5 +.\" --- Namespaces +.ES +.fi +\*(CDA +\*(FIqualified name\fP +consists of a two simple identifiers joined by a double colon +(\*(FC::\fP). +The left identifier is the namespace and the right one +is the variable within it. +All non-qualified names are treated as if in the +``current'' namespace; the default namespace is \*(FCawk\fP. +However, simple identifiers consisting solely of upper-case +letters are forced into the +\*(FCawk\fP +namespace. +You change the current namespace with an +\*(FC@namespace "\*(FIname\^\*(FC"\*(FR +directive.\*(CB +.EB "\s+2\f(HBNAMESPACES\*(FR\s0" .BT @@ -13,7 +13,7 @@ . if \w'\(rq' .ds rq "\(rq . \} .\} -.TH GAWK 1 "Nov 26 2018" "Free Software Foundation" "Utility Commands" +.TH GAWK 1 "Dec 12 2018" "Free Software Foundation" "Utility Commands" .SH NAME gawk \- pattern scanning and processing language .SH SYNOPSIS @@ -132,6 +132,9 @@ Multiple (or .BR \-\^\-file ) options may be used. +Files read with +.B \-f +are treated as if they begin with an implict \fB@namespace "awk"\fR statement. .TP .PD 0 .BI \-F " fs" @@ -253,6 +256,9 @@ and options) with source code entered on the command line. It is intended primarily for medium to large \*(AK programs used in shell scripts. +Each argument supplied via +.B \-e +is treated as if it begins with an implict \fB@namespace "awk"\fR statement. .TP .PD 0 .BI "\-E " file @@ -310,6 +316,9 @@ be made after appending the suffix. The file will be loaded only once (i.e., duplicates are eliminated), and the code does not constitute the main program source. +Files read with +.B \-i +are treated as if they begin with an implict \fB@namespace "awk"\fR statement. .TP .PD 0 .BI "\-l " lib @@ -577,9 +586,11 @@ pattern-action statements, and optional function definitions. .RS .PP -\fB@include "\fIfilename\fB" +\fB@include "\fIfilename\^\fB" +.br +\fB@load "\fIfilename\^\fB" .br -\fB@load "\fIfilename\fB" +\fB@namespace "\fIname\^\fB" .br \fIpattern\fB { \fIaction statements\fB }\fR .br @@ -1202,6 +1213,28 @@ doesn't know yet). The identifier is a user-defined function. .RE .TP +\fBPROCINFO["platform"]\fP +A string indicating the platform for which +.I gawk +was compiled. It is one of: +.RS +.TP +\fB"vms"\fR +OpenVMS or Vax/VMS. +.TP +\fB"macosx"\fR +Mac OS X. +.TP +\fB"cygwin"\fR, \fB"djgpp"\fR, \fB"mingw"\fR +Microsoft Windows, using either Cygwin, DJGPP, or MinGW, respectively. +.TP +\fB"os2"\fR +OS/2. +.TP +\fB"posix"\fR +GNU/Linux and legacy Unix systems. +.RE +.TP \fBPROCINFO["pgrpid"]\fP The process group ID of the current process. .TP @@ -1403,7 +1436,8 @@ You may not use the .B delete statement with the .B SYMTAB -array. +array, nor assign to elements with an index that is +not a variable name. .TP .B TEXTDOMAIN The text domain of the \*(AK program; used to find the localized @@ -1497,6 +1531,37 @@ You can do this by creating an element in the subarray and then deleting it with the .B delete statement. +.SS Namespaces +.I Gawk +provides a simple +.I namespace +facility to help work around the fact that all variables in +AWK are global. +.PP +A +.I "qualified name" +consists of a two simple identifiers joined by a double colon +.RB ( :: ). +The left-hand identifier represents the namespace and the right-hand +identifier is the variable within it. +All simple (non-qualified) names are considered to be in the +``current'' namespace; the default namespace is +.BR awk . +However, simple identifiers consisting solely of upper-case +letters are forced into the +.B awk +namespace, even if the current namespace is different. +.PP +You change the current namespace with an +\fB@namespace "\fIname\^\fB"\fR +directive. +.PP +The standard predefined builtin function names may not be used as +namespace names. The names of additional functions provided by +.I gawk +may be used as namespace names or as simple identifiers in other +namespaces. +For more details, see \*(EP. .SS Variable Typing And Conversion .PP Variables and fields @@ -1645,7 +1710,7 @@ regular expression constants. Thus, .B /a\e52b/ is equivalent to .BR /a\e*b/ . -.SS "Regexp Constants" +.SS Regexp Constants A regular expression constant is a sequence of characters enclosed between forward slashes (like .BR /value/ ). diff --git a/doc/gawk.info b/doc/gawk.info index 3c269bad..b55ef0bb 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -88,6 +88,7 @@ in (a) below. A copy of the license is included in the section entitled * Internationalization:: Getting 'gawk' to speak your language. * Debugger:: The 'gawk' debugger. +* Namespaces:: How namespaces work in 'gawk'. * Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with 'gawk'. * Dynamic Extensions:: Adding new built-in functions to @@ -522,6 +523,15 @@ in (a) below. A copy of the license is included in the section entitled * Readline Support:: Readline support. * Limitations:: Limitations and future plans. * Debugging Summary:: Debugging summary. +* Global Namespace:: The global namespace in standard 'awk'. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other 'gawk' features. +* Namespace Summary:: Summarizing namespaces. * Computer Arithmetic:: A quick intro to computer math. * Math Definitions:: Defining terms used. * MPFR features:: The MPFR features in 'gawk'. @@ -1098,6 +1108,10 @@ in *note Sample Programs::, should be of interest. - *note Debugger::, describes the 'gawk' debugger. + - *note Namespaces::, describes how 'gawk' allows variables + and/or functions of the same name to be in different + namespaces. + - *note Arbitrary Precision Arithmetic::, describes advanced arithmetic facilities. @@ -2481,6 +2495,10 @@ The following list describes options mandated by the POSIX standard: the 'awk' program consists of the concatenation of the contents of each specified SOURCE-FILE. + Files named with '-i' are treated as if they had '@namespace "awk"' + at their beginning. *Note Changing The Namespace::, for more + information. + '-v VAR=VAL' '--assign VAR=VAL' Set the variable VAR to the value VAL _before_ execution of the @@ -2577,15 +2595,19 @@ The following list describes options mandated by the POSIX standard: character (even if it doesn't). This makes building the total program easier. - CAUTION: At the moment, there is no requirement that each - PROGRAM-TEXT be a full syntactic unit. I.e., the following - currently works: + CAUTION: Prior to version 5.0, there was no requirement that + each PROGRAM-TEXT be a full syntactic unit. I.e., the + following worked: $ gawk -e 'BEGIN { a = 5 ;' -e 'print a }' -| 5 - However, this could change in the future, so it's not a good - idea to rely upon this feature. + However, this is no longer true. If you have any scripts that + rely upon this feature, you should revise them. + + This is because each PROGRAM-TEXT is treated as if it had + '@namespace "awk"' at its beginning. *Note Changing The + Namespace::, for more information. '-E' FILE '--exec' FILE @@ -2634,6 +2656,10 @@ The following list describes options mandated by the POSIX standard: processing an '-i' argument, 'gawk' still expects to find the main source code via the '-f' option or on the command line. + Files named with '-i' are treated as if they had '@namespace "awk"' + at their beginning. *Note Changing The Namespace::, for more + information. + '-l' EXT '--load' EXT Load a dynamic extension named EXT. Extensions are stored as @@ -3259,6 +3285,10 @@ from web pages. The rules for finding a source file described in *note AWKPATH Variable:: also apply to files loaded with '@include'. + Finally, files included with '@include' are treated as if they had +'@namespace "awk"' at their beginning. *Note Changing The Namespace::, +for more information. + File: gawk.info, Node: Loading Shared Libraries, Next: Obsolete, Prev: Include Files, Up: Invoking Gawk @@ -11045,6 +11075,27 @@ they are not special: after it has finished parsing the program; they are _not_ updated while the program runs. + 'PROCINFO["platform"]' + This element gives a string indicating the platform for which + 'gawk' was compiled. The value will be one of the following: + + '"vms"' + OpenVMS or Vax/VMS. + + '"djgpp"' + '"mingw"' + Microsoft Windows, using either DJGPP or MinGW, + respectively. + + '"os2"' + OS/2. + + '"os390"' + OS/390. + + '"posix"' + GNU/Linux, Cygwin, Mac OS X, and legacy Unix systems. + 'PROCINFO["pgrpid"]' The process group ID of the current process. @@ -11171,15 +11222,14 @@ they are not special: test if an element in 'SYMTAB' is an array. Also, you may not use the 'delete' statement with the 'SYMTAB' array. - You may use an index for 'SYMTAB' that is not a predefined - identifier: + Prior to version 5.0 of 'gawk', you could use an index for 'SYMTAB' + that was not a predefined identifier: SYMTAB["xxx"] = 5 print SYMTAB["xxx"] - This works as expected: in this case 'SYMTAB' acts just like a - regular array. The only difference is that you can't then delete - 'SYMTAB["xxx"]'. + This no longer works, instead producing a fatal error, as it led to + rampant confusion. The 'SYMTAB' array is more interesting than it looks. Andrew Schorr points out that it effectively gives 'awk' data pointers. @@ -15293,6 +15343,10 @@ and '_pw_count'. conventions. You are not required to write your programs this way--we merely recommend that you do so. + Beginning with version 5.0, 'gawk' provides a powerful mechanism for +solving the problems described in this section: "namespaces". +Namespaces and their use are described in detail in *note Namespaces::. + ---------- Footnotes ---------- (1) Although all the library routines could have been rewritten to @@ -18221,6 +18275,10 @@ line of input data: close(outputfile) } + As a side note, 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. + File: gawk.info, Node: Wc Program, Prev: Uniq Program, Up: Clones @@ -20776,7 +20834,8 @@ output. They are as follows: structure of the program and the precedence rules. For example, '(3 + 5) * 4' means add three and five, then multiply the total by four. However, '3 + 5 * 4' has no parentheses, and means '3 + (5 * - 4)'. + 4)'. However, explicit parentheses in the source program are + retained. * Parentheses are used around the arguments to 'print' and 'printf' only when the 'print' or 'printf' statement is followed by a @@ -20798,10 +20857,11 @@ representation. Also, things such as: come out as: /foo/ { - print $0 + print } -which is correct, but possibly unexpected. +which is correct, but possibly unexpected. (If a program uses both +'print $0' and plain 'print', that distinction is retained.) Besides creating profiles when a program has completed, 'gawk' can produce a profile while it is running. This is useful if your 'awk' @@ -20857,7 +20917,10 @@ without any execution counts. 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.(1) +source code. However, no comments should be lost. Also, 'gawk' does +the best it can to preserve the distinction between comments at the end +of a statement and comments on lines by themselves. This isn't always +perfect, though. However, as a deliberate design decision, profiling output _omits_ the original program's comments. This allows you to focus on the @@ -20877,14 +20940,6 @@ disable 'gawk''s default optimizations. numeric constants; if you used an octal or hexadecimal value in your source code, it will appear that way in the output. - ---------- Footnotes ---------- - - (1) 'gawk' does the best it can to preserve the distinction between -comments at the end of a statement and comments on lines by themselves. -Due to implementation constraints, it does not always do so correctly, -particularly for 'switch' statements. The 'gawk' maintainers hope to -improve this in a subsequent release. - File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanced Features @@ -21595,7 +21650,7 @@ File: gawk.info, Node: I18N Summary, Prev: Gawk I18N, Up: Internationalizatio translations for its messages. -File: gawk.info, Node: Debugger, Next: Arbitrary Precision Arithmetic, Prev: Internationalization, Up: Top +File: gawk.info, Node: Debugger, Next: Namespaces, Prev: Internationalization, Up: Top 14 Debugging 'awk' Programs *************************** @@ -22672,9 +22727,389 @@ File: gawk.info, Node: Debugging Summary, Prev: Limitations, Up: Debugger debugged, but occasionally it can. -File: gawk.info, Node: Arbitrary Precision Arithmetic, Next: Dynamic Extensions, Prev: Debugger, Up: Top +File: gawk.info, Node: Namespaces, Next: Arbitrary Precision Arithmetic, Prev: Debugger, Up: Top + +15 Namespaces in 'gawk' +*********************** + +This major node describes a feature that is specific to 'gawk'. + +* Menu: + +* Global Namespace:: The global namespace in standard 'awk'. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other 'gawk' features. +* Namespace Summary:: Summarizing namespaces. + + +File: gawk.info, Node: Global Namespace, Next: Qualified Names, Up: Namespaces + +15.1 Standard 'awk''s Single Namespace +====================================== + +In standard 'awk', there is a single, global, "namespace". This means +that _all_ function names and global variable names must be unique. For +example, two different 'awk' source files cannot both define a function +named 'min()', or define the same identifier, used as a scalar in one +and as an array in the other. + + This situation is okay when programs are small, say a few hundred +lines, or even a few thousand, but it prevents the development of +reusable libraries of 'awk' functions, and can inadvertently cause +independently-developed library files to accidentally step on each +other's "private" global variables (*note Library Names::). + + Most other programming languages solve this issue by providing some +kind of namespace control: a way to say "this function is in namespace +XXX, and that function is in namespace YYY." (Of course, there is then +still a single namespace for the namespaces, but the hope is that there +are much fewer namespaces in use by any given program, and thus much +less chance for collisions.) These facilities are sometimes referred to +as "packages" or "modules". + + Starting with version 5.0, 'gawk' provides a simple mechanism to put +functions and global variables into separate namespaces. + + +File: gawk.info, Node: Qualified Names, Next: Default Namespace, Prev: Global Namespace, Up: Namespaces + +15.2 Qualified Names +==================== + +A "qualified name" is an identifier that includes a namespace name, the +namespace separator '::', and a "component" name. For example, one +might have a function named 'posix::getpid()'. Here, the namespace is +'posix' and the function name within the namespace (the component) is +'getpid()'. The namespace and component names are separated by a +double-colon. Only one such separator is allowed in a qualified name. + + NOTE: Unlike C++, the '::' is _not_ an operator. No spaces are + allowed between the namespace name, the '::', and the component + name. + + You must use qualified names from one namespace to access variables +and functions in another. This is especially important when using +variable names to index the special 'SYMTAB' array (*note Auto-set::), +and when making indirect function calls (*note Indirect Calls::). + + +File: gawk.info, Node: Default Namespace, Next: Changing The Namespace, Prev: Qualified Names, Up: Namespaces + +15.3 The Default Namespace +========================== + +The default namespace, not surprisingly, is 'awk'. All of the +predefined 'awk' and 'gawk' variables are in this namespace, and thus +have qualified names like 'awk::ARGC', 'awk::NF', and so on. + + Furthermore, even when you have changed the namespace for your +current source file (*note Changing The Namespace::), 'gawk' forces +unqualified identifiers whose names are all uppercase letters to be in +the 'awk' namespace. This makes it possible for you to easily reference +'gawk''s global variables from different namespaces. It also keeps your +code looking natural. + + +File: gawk.info, Node: Changing The Namespace, Next: Naming Rules, Prev: Default Namespace, Up: Namespaces + +15.4 Changing The Namespace +=========================== + +In order to set the current namespace, use an '@namespace' directive at +the top level of your program: + + @namespace "passwd" + + BEGIN { ... } + ... + + After this directive, all simple non-completely-uppercase identifiers +are placed into the 'passwd' namespace. + + You can change the namespace multiple times within a single source +file, although this is likely to become confusing if you do it too much. + + NOTE: Association of unqualified identifiers to a namespace is + handled while 'gawk' parses your program, _before_ it starts to + run. There is no concept of a "current" namespace once your + program starts executing. Be sure you understand this. + + Each source file for '-i' and '-f' starts out with an implicit +'@namespace "awk"'. Similarly, each chunk of command-line code supplied +with '-e' has such an implicit initial statement (*note Options::). + + Files included with '@include' (*note Include Files::) "push" and +"pop" the current namespace. That is, each '@include' saves the current +namespace and starts over with an implicit '@namespace "awk"' which +remains in effect until an explicit '@namespace' directive is seen. +When 'gawk' finishes processing the included file, the saved namespace +is restored and processing continues where it left off in the original +file. + + The use of '@namespace' has no influence upon the order of execution +of 'BEGIN', 'BEGINFILE', 'END', and 'ENDFILE' rules. + + +File: gawk.info, Node: Naming Rules, Next: Internal Name Management, Prev: Changing The Namespace, Up: Namespaces + +15.5 Namespace and Component Naming Rules +========================================= + +A number of rules apply to the namespace and component names, as +follows. + + * It is a syntax error to use qualified names for function parameter + names. + + * It is a syntax error to use any standard 'awk' reserved word (such + as 'if' or 'for'), or the name of any standard built-in function + (such as 'sin()' or 'gsub()') as either part of a qualified name. + Thus, the following produces a syntax error: + + @namespace "example" + + function gsub(str, pat, result) { ... } + + * Outside the 'awk' namespace, the names of the additional 'gawk' + built-in functions (such as 'gensub()' or 'strftime()') _may_ be + used as component names. The same set of names may be used as + namespace names, although this has the potential to be confusing. + + * The additional 'gawk' built-in functions may still be called from + outside the 'awk' namespace by qualifying them. For example, + 'awk::systime()'. Here is a somewhat silly example demonstrating + this rule and the previous one: + + BEGIN { + print "in awk namespace, systime() =", systime() + } + + @namespace "testing" + + function systime() + { + print "in testing namespace, systime() =", awk::systime() + } + + BEGIN { + systime() + } + + + When run, it produces output like this: + + $ gawk -f systime.awk + -| in awk namespace, systime() = 1500488503 + -| in testing namespace, systime() = 1500488503 + + * 'gawk' pre-defined variable names may be used: 'NF::NR' is valid, + if possibly not all that useful. + + +File: gawk.info, Node: Internal Name Management, Next: Namespace Example, Prev: Naming Rules, Up: Namespaces + +15.6 Internal Name Management +============================= + +For backwards compatibility, all identifiers in the 'awk' namespace are +stored internally as unadorned identifiers (that is, without a leading +'awk::'). This is mainly relevant when using such identifiers as +indices for 'SYMTAB', 'FUNCTAB', and 'PROCINFO["identifiers"]' (*note +Auto-set::), and for use in indirect function calls (*note Indirect +Calls::). + + In program code, to refer to variables and functions in the 'awk' +namespace from another namespace, you must still use the 'awk::' prefix. +For example: + + @namespace "awk" This is the default namespace + + BEGIN { + Title = "My Report" Qualified name is awk::Title + } + + @namespace "report" Now in report namespace + + function compute() This is really report::compute() + { + print awk::Title But would be SYMTAB["Title"] + ... + } + + +File: gawk.info, Node: Namespace Example, Next: Namespace And Features, Prev: Internal Name Management, Up: Namespaces + +15.7 Namespace Example +====================== + +The following example is a revised version of the suite of routines +developed in *note Passwd Functions::. See there for an explanation of +how the code works. + + The formulation here, due mainly to Andrew Schorr, is rather elegant. +All of the implementation functions and variables are in the 'passwd' +namespace, whereas the main interface functions are defined in the 'awk' +namespace. + + # ns_passwd.awk --- access password file information -15 Arithmetic and Arbitrary-Precision Arithmetic with 'gawk' + @namespace "passwd" + + BEGIN { + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" + } + + function Init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) + { + if (Inited) + return + + oldfs = FS + oldrs = RS + olddol0 = $0 + using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (PROCINFO["FS"] == "FPAT") + FS = ":" + RS = "\n" + + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) { + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + } + close(pwcat) + Count = 0 + Inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 + } + + function awk::getpwnam(name) + { + Init() + return Byname[name] + } + + function awk::getpwuid(uid) + { + Init() + return Byuid[uid] + } + + function awk::getpwent() + { + Init() + if (Count < Total) + return Bycount[++Count] + return "" + } + + function awk::endpwent() + { + Count = 0 + } + + As you can see, this version also follows the convention mentioned in +*note Library Names::, whereby global variable and function names start +with a capital letter. + + Here is a simple test program. Since it's in a separate file, +unadorned identifiers are sought for in the 'awk' namespace: + + BEGIN { + while ((p = getpwent()) != "") + print p + } + + + Here's what happens when it's run: + + $ gawk -f ns_passwd.awk -f testpasswd.awk + -| root:x:0:0:root:/root:/bin/bash + -| daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin + -| bin:x:2:2:bin:/bin:/usr/sbin/nologin + -| sys:x:3:3:sys:/dev:/usr/sbin/nologin + ... + + +File: gawk.info, Node: Namespace And Features, Next: Namespace Summary, Prev: Namespace Example, Up: Namespaces + +15.8 Namespaces and Other 'gawk' Features +========================================= + +This minor node looks briefly at how the namespace facility interacts +with other important 'gawk' features. + + The profiler and pretty-printer (*note Profiling::) have been +enhanced to understand namespaces and the namespace naming rules +presented in *note Naming Rules::. In particular, the output groups +functions in the same namespace together, and has '@namespace' +directives in front of rules as necessary. This allows component names +to be simple identifiers, instead of using qualified identifiers +everywhere. + + Interaction with the debugger (*note Debugging::) has not had to +change (at least as of this writing). Some of the internal byte codes +changed in order to accommodate namespaces, and the debugger's 'dump' +command was adjusted to match. + + The extension API (*note Dynamic Extensions::) has always allowed for +placing functions into a different namespace, although this was not +previously implemented. However, the symbol lookup and symbol update +routines did not have provision for including a namespace. That has now +been corrected (*note Symbol table by name::). *Note Extension Sample +Inplace::, for a nice example of an extension that leverages a namespace +shared by cooperating 'awk' and C code. + + +File: gawk.info, Node: Namespace Summary, Prev: Namespace And Features, Up: Namespaces + +15.9 Summary +============ + + * Standard 'awk' provides a single namespace for all global + identifiers (scalars, arrays, and functions). This is limiting + when one wants to develop libraries of reusable functions or + function suites. + + * 'gawk' provides multiple namespaces by using qualified names: names + consisting of a namespace name, a double colon, '::', and a + component name. Namespace names might still possibly conflict, but + this is true of any language providing namespaces, modules, or + packages. + + * The default namespace is 'awk'. The rules for namespace and + component names are provided in *note Naming Rules::. The rules + are designed in such a way as to make namespace-aware code continue + to look and work naturally while still providing the necessary + power and flexibility. + + * Other parts of 'gawk' have been extended as necessary to integrate + namespaces smoothly with their operation. This applies most + notably to the profiler / pretty-printer (*note Profiling::) and to + the extension facility (*note Dynamic Extensions::). + + * Overall, the namespace facility was designed and implemented such + that backwards compatibility is paramount. Programs that don't use + namespaces should see absolutely no difference in behavior when run + by a namespace-capable version of 'gawk'. + + +File: gawk.info, Node: Arbitrary Precision Arithmetic, Next: Dynamic Extensions, Prev: Namespaces, Up: Top + +16 Arithmetic and Arbitrary-Precision Arithmetic with 'gawk' ************************************************************ This major node introduces some basic concepts relating to how computers @@ -22705,7 +23140,7 @@ are not quite in agreement. File: gawk.info, Node: Computer Arithmetic, Next: Math Definitions, Up: Arbitrary Precision Arithmetic -15.1 A General Description of Computer Arithmetic +16.1 A General Description of Computer Arithmetic ================================================= Until now, we have worked with data as either numbers or strings. @@ -22776,7 +23211,7 @@ double-precision floating-point values occupy 64 bits. (Quadruple-precision floating point values also exist. They occupy 128 bits, but such numbers are not available in 'awk'.) Floating-point values are always signed. The possible ranges of values are shown in -*note Table 15.1: table-numeric-ranges. and *note Table 15.2: +*note Table 16.1: table-numeric-ranges. and *note Table 16.2: table-floating-point-ranges. Representation Minimum value Maximum value @@ -22788,7 +23223,7 @@ integer 64-bit unsigned 0 18,446,744,073,709,551,615 integer -Table 15.1: Value ranges for integer representations +Table 16.1: Value ranges for integer representations Representation Minimum Minimum finite Maximum finite positive value value @@ -22801,7 +23236,7 @@ floating-point Quadruple-precision 3.362103e-4932 -1.189731e+4932 1.189731e+4932 floating-point -Table 15.2: Approximate value ranges for floating-point number +Table 16.2: Approximate value ranges for floating-point number representations ---------- Footnotes ---------- @@ -22811,7 +23246,7 @@ representations File: gawk.info, Node: Math Definitions, Next: MPFR features, Prev: Computer Arithmetic, Up: Arbitrary Precision Arithmetic -15.2 Other Stuff to Know +16.2 Other Stuff to Know ======================== The rest of this major node uses a number of terms. Here are some @@ -22891,7 +23326,7 @@ IEEE 754 types are 32-bit single precision, 64-bit double precision, and precision formats to allow greater precisions and larger exponent ranges. ('awk' uses only the 64-bit double-precision format.) - *note Table 15.3: table-ieee-formats. lists the precision and + *note Table 16.3: table-ieee-formats. lists the precision and exponent field values for the basic IEEE 754 binary formats. Name Total bits Precision Minimum Maximum @@ -22901,7 +23336,7 @@ Single 32 24 -126 +127 Double 64 53 -1022 +1023 Quadruple 128 113 -16382 +16383 -Table 15.3: Basic IEEE format values +Table 16.3: Basic IEEE format values NOTE: The precision numbers include the implied leading one that gives them one extra bit of significand. @@ -22914,7 +23349,7 @@ 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-Precision Arithmetic Features in 'gawk' +16.3 Arbitrary-Precision Arithmetic Features in 'gawk' ====================================================== By default, 'gawk' uses the double-precision floating-point values @@ -22952,7 +23387,7 @@ information. File: gawk.info, Node: FP Math Caution, Next: Arbitrary Precision Integers, Prev: MPFR features, Up: Arbitrary Precision Arithmetic -15.4 Floating-Point Arithmetic: Caveat Emptor! +16.4 Floating-Point Arithmetic: Caveat Emptor! ============================================== Math class is tough! @@ -22986,7 +23421,7 @@ in computer science. File: gawk.info, Node: Inexactness of computations, Next: Getting Accuracy, Up: FP Math Caution -15.4.1 Floating-Point Arithmetic Is Not Exact +16.4.1 Floating-Point Arithmetic Is Not Exact --------------------------------------------- Binary floating-point representations and arithmetic are inexact. @@ -23007,7 +23442,7 @@ be sure of the number of significant decimal places in the final result. File: gawk.info, Node: Inexact representation, Next: Comparing FP Values, Up: Inexactness of computations -15.4.1.1 Many Numbers Cannot Be Represented Exactly +16.4.1.1 Many Numbers Cannot Be Represented Exactly ................................................... So, before you start to write any code, you should think about what you @@ -23038,7 +23473,7 @@ previous example, produces an output identical to the input. File: gawk.info, Node: Comparing FP Values, Next: Errors accumulate, Prev: Inexact representation, Up: Inexactness of computations -15.4.1.2 Be Careful Comparing Values +16.4.1.2 Be Careful Comparing Values .................................... Because the underlying representation can be a little bit off from the @@ -23069,7 +23504,7 @@ in case someone passes in a negative delta value. File: gawk.info, Node: Errors accumulate, Prev: Comparing FP Values, Up: Inexactness of computations -15.4.1.3 Errors Accumulate +16.4.1.3 Errors Accumulate .......................... The loss of accuracy during a single computation with floating-point @@ -23117,7 +23552,7 @@ representations yield an unexpected result: File: gawk.info, Node: Getting Accuracy, Next: Try To Round, Prev: Inexactness of computations, Up: FP Math Caution -15.4.2 Getting the Accuracy You Need +16.4.2 Getting the Accuracy You Need ------------------------------------ Can arbitrary-precision arithmetic give exact results? There are no @@ -23178,7 +23613,7 @@ hand is often the correct approach in such situations. File: gawk.info, Node: Try To Round, Next: Setting precision, Prev: Getting Accuracy, Up: FP Math Caution -15.4.3 Try a Few Extra Bits of Precision and Rounding +16.4.3 Try a Few Extra Bits of Precision and Rounding ----------------------------------------------------- Instead of arbitrary-precision floating-point arithmetic, often all you @@ -23205,7 +23640,7 @@ iterations: File: gawk.info, Node: Setting precision, Next: Setting the rounding mode, Prev: Try To Round, Up: FP Math Caution -15.4.4 Setting the Precision +16.4.4 Setting the Precision ---------------------------- 'gawk' uses a global working precision; it does not keep track of the @@ -23214,7 +23649,7 @@ 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 predefined variable 'PREC'. You can also set the value to one of the predefined case-insensitive strings shown in -*note Table 15.4: table-predefined-precision-strings, to emulate an IEEE +*note Table 16.4: table-predefined-precision-strings, to emulate an IEEE 754 binary format. 'PREC' IEEE 754 binary format @@ -23225,7 +23660,7 @@ set the value to one of the predefined case-insensitive strings shown in '"quad"' Basic 128-bit quadruple precision '"oct"' 256-bit octuple precision -Table 15.4: Predefined precision strings for 'PREC' +Table 16.4: Predefined precision strings for 'PREC' The following example illustrates the effects of changing precision on arithmetic operations: @@ -23262,12 +23697,12 @@ on arithmetic operations: File: gawk.info, Node: Setting the rounding mode, Prev: Setting precision, Up: FP Math Caution -15.4.5 Setting the Rounding Mode +16.4.5 Setting the Rounding Mode -------------------------------- The 'ROUNDMODE' variable provides program-level control over the rounding mode. The correspondence between 'ROUNDMODE' and the IEEE -rounding modes is shown in *note Table 15.5: table-gawk-rounding-modes. +rounding modes is shown in *note Table 16.5: table-gawk-rounding-modes. Rounding mode IEEE name 'ROUNDMODE' --------------------------------------------------------------------------- @@ -23277,10 +23712,10 @@ Round toward negative infinity 'roundTowardNegative' '"D"' or '"d"' Round toward zero 'roundTowardZero' '"Z"' or '"z"' Round away from zero '"A"' or '"a"' -Table 15.5: 'gawk' rounding modes +Table 16.5: 'gawk' rounding modes 'ROUNDMODE' has the default value '"N"', which selects the IEEE 754 -rounding mode 'roundTiesToEven'. In *note Table 15.5: +rounding mode 'roundTiesToEven'. In *note Table 16.5: table-gawk-rounding-modes, the value '"A"' selects rounding away from zero. This is only available if your version of the MPFR library supports it; otherwise, setting 'ROUNDMODE' to '"A"' has no effect. @@ -23372,7 +23807,7 @@ round halfway cases for 'printf'. File: gawk.info, Node: Arbitrary Precision Integers, Next: Checking for MPFR, Prev: FP Math Caution, Up: Arbitrary Precision Arithmetic -15.5 Arbitrary-Precision Integer Arithmetic with 'gawk' +16.5 Arbitrary-Precision Integer Arithmetic with 'gawk' ======================================================= When given the '-M' option, 'gawk' performs all integer arithmetic using @@ -23450,7 +23885,7 @@ Wolfram Web Resource File: gawk.info, Node: Checking for MPFR, Next: POSIX Floating Point Problems, Prev: Arbitrary Precision Integers, Up: Arbitrary Precision Arithmetic -15.6 How To Check If MPFR Is Available +16.6 How To Check If MPFR Is Available ====================================== Occasionally, you might like to be able to check if 'gawk' was invoked @@ -23491,7 +23926,7 @@ arbitrary-precision arithmetic is available: File: gawk.info, Node: POSIX Floating Point Problems, Next: Floating point summary, Prev: Checking for MPFR, Up: Arbitrary Precision Arithmetic -15.7 Standards Versus Existing Practice +16.7 Standards Versus Existing Practice ======================================= Historically, 'awk' has converted any nonnumeric-looking string to the @@ -23585,7 +24020,7 @@ described: '+inf', '-inf', '+nan', or '-nan'. Similarly, in POSIX mode, File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Problems, Up: Arbitrary Precision Arithmetic -15.8 Summary +16.8 Summary ============ * Most computer arithmetic is done using either integers or @@ -23638,7 +24073,7 @@ File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Prob File: gawk.info, Node: Dynamic Extensions, Next: Language History, Prev: Arbitrary Precision Arithmetic, Up: Top -16 Writing Extensions for 'gawk' +17 Writing Extensions for 'gawk' ******************************** It is possible to add new functions written in C or C++ to 'gawk' using @@ -23672,7 +24107,7 @@ sample extensions are automatically built and installed when 'gawk' is. File: gawk.info, Node: Extension Intro, Next: Plugin License, Up: Dynamic Extensions -16.1 Introduction +17.1 Introduction ================= An "extension" (sometimes called a "plug-in") is a piece of external @@ -23699,7 +24134,7 @@ and design. File: gawk.info, Node: Plugin License, Next: Extension Mechanism Outline, Prev: Extension Intro, Up: Dynamic Extensions -16.2 Extension Licensing +17.2 Extension Licensing ======================== Every dynamic extension must be distributed under a license that is @@ -23719,12 +24154,12 @@ symbol exists in the global scope. Something like this is enough: File: gawk.info, Node: Extension Mechanism Outline, Next: Extension API Description, Prev: Plugin License, Up: Dynamic Extensions -16.3 How It Works at a High Level +17.3 How It Works at a High Level ================================= Communication between 'gawk' and an extension is two-way. First, when an extension is loaded, 'gawk' passes it a pointer to a 'struct' whose -fields are function pointers. This is shown in *note Figure 16.1: +fields are function pointers. This is shown in *note Figure 17.1: figure-load-extension. @@ -23752,12 +24187,12 @@ figure-load-extension. gawk Main Program Address Space Extension" -Figure 16.1: Loading the extension +Figure 17.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 functions. This is shown in *note Figure 16.2: +"registering" new functions. This is shown in *note Figure 17.2: figure-register-new-function. @@ -23773,13 +24208,13 @@ figure-register-new-function. gawk Main Program Address Space Extension" -Figure 16.2: Registering a new function +Figure 17.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 the new feature ('do_chdir()', for example). 'gawk' associates the function pointer with a name and can then call it, using a defined -calling convention. This is shown in *note Figure 16.3: +calling convention. This is shown in *note Figure 17.3: figure-call-new-function. @@ -23796,7 +24231,7 @@ figure-call-new-function. gawk Main Program Address Space Extension" -Figure 16.3: Calling the new function +Figure 17.3: Calling the new function The 'do_XXX()' function, in turn, then uses the function pointers in the API 'struct' to do its work, such as updating variables or arrays, @@ -23828,7 +24263,7 @@ Example::) and also in the 'testext.c' code for testing the APIs. File: gawk.info, Node: Extension API Description, Next: Finding Extensions, Prev: Extension Mechanism Outline, Up: Dynamic Extensions -16.4 API Description +17.4 API Description ==================== C or C++ code for an extension must include the header file 'gawkapi.h', @@ -23860,7 +24295,7 @@ API in detail. File: gawk.info, Node: Extension API Functions Introduction, Next: General Data Types, Up: Extension API Description -16.4.1 Introduction +17.4.1 Introduction ------------------- Access to facilities within 'gawk' is achieved by calling through @@ -23915,7 +24350,9 @@ operations: * The following types, macros, and/or functions are referenced in 'gawkapi.h'. For correct use, you must therefore include the - corresponding standard header file _before_ including 'gawkapi.h': + corresponding standard header file _before_ including 'gawkapi.h'. + The list of macros and related header files is shown in *note Table + 17.1: table-api-std-headers. C entity Header file ------------------------------------------- @@ -23928,6 +24365,8 @@ operations: 'size_t' '<sys/types.h>' 'struct stat' '<sys/stat.h>' + Table 17.1: Standard header files needed by API + Due to portability concerns, especially to systems that are not fully standards-compliant, it is your responsibility to include the correct files in the correct way. This requirement is necessary in @@ -23994,7 +24433,7 @@ macros as if they were functions. 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 +17.4.2 General-Purpose Data Types --------------------------------- I have a true love/hate relationship with unions. @@ -24194,7 +24633,7 @@ See also the entry for "Cookie" in the *note Glossary::. File: gawk.info, Node: Memory Allocation Functions, Next: Constructor Functions, Prev: General Data Types, Up: Extension API Description -16.4.3 Memory Allocation Functions and Convenience Macros +17.4.3 Memory Allocation Functions and Convenience Macros --------------------------------------------------------- The API provides a number of "memory allocation" functions for @@ -24301,7 +24740,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.4 Constructor Functions +17.4.4 Constructor Functions ---------------------------- The API provides a number of "constructor" functions for creating string @@ -24376,7 +24815,7 @@ code would use them: File: gawk.info, Node: Registration Functions, Next: Printing Messages, Prev: Constructor Functions, Up: Extension API Description -16.4.5 Registration Functions +17.4.5 Registration Functions ----------------------------- This minor node describes the API functions for registering parts of @@ -24394,7 +24833,7 @@ your extension with 'gawk'. File: gawk.info, Node: Extension Functions, Next: Exit Callback Functions, Up: Registration Functions -16.4.5.1 Registering An Extension Function +17.4.5.1 Registering An Extension Function .......................................... Extension functions are described by the following record: @@ -24473,9 +24912,11 @@ register it with 'gawk' using this API function: 'awk_bool_t add_ext_func(const char *name_space, awk_ext_func_t *func);' This function returns true upon success, false otherwise. The - 'name_space' parameter is currently not used; you should pass in an - empty string ('""'). The 'func' pointer is the address of a - 'struct' representing your function, as just described. + 'name_space' parameter is the namespace in which to place the + function (*note Namespaces::). Use an empty string ('""') or + '"awk"' to place the function in the default 'awk' namespace. The + 'func' pointer is the address of a 'struct' representing your + function, as just described. 'gawk' does not modify what 'func' points to, but the extension function itself receives this pointer and can modify what it points @@ -24507,7 +24948,7 @@ A minimum number of arguments is required, and no more than a maximum is allowed File: gawk.info, Node: Exit Callback Functions, Next: Extension Version String, Prev: Extension Functions, Up: Registration Functions -16.4.5.2 Registering An Exit Callback Function +17.4.5.2 Registering An Exit Callback Function .............................................. An "exit callback" function is a function that 'gawk' calls before it @@ -24537,7 +24978,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.5.3 Registering An Extension Version String +17.4.5.3 Registering An Extension Version String ................................................ You can register a version string that indicates the name and version of @@ -24554,7 +24995,7 @@ invoked with the '--version' option. File: gawk.info, Node: Input Parsers, Next: Output Wrappers, Prev: Extension Version String, Up: Registration Functions -16.4.5.4 Customized Input Parsers +17.4.5.4 Customized Input Parsers ................................. By default, 'gawk' reads text files as its input. It uses the value of @@ -24832,7 +25273,7 @@ example. File: gawk.info, Node: Output Wrappers, Next: Two-way processors, Prev: Input Parsers, Up: Registration Functions -16.4.5.5 Customized Output Wrappers +17.4.5.5 Customized Output Wrappers ................................... An "output wrapper" is the mirror image of an input parser. It allows @@ -24938,7 +25379,7 @@ just use normally. File: gawk.info, Node: Two-way processors, Prev: Output Wrappers, Up: Registration Functions -16.4.5.6 Customized Two-way Processors +17.4.5.6 Customized Two-way Processors ...................................... A "two-way processor" combines an input parser and an output wrapper for @@ -24992,7 +25433,7 @@ and 'XXX_take_control_of()'. File: gawk.info, Node: Printing Messages, Next: Updating ERRNO, Prev: Registration Functions, Up: Extension API Description -16.4.6 Printing Messages +17.4.6 Printing Messages ------------------------ You can print different kinds of warning messages from your extension, @@ -25026,7 +25467,7 @@ the pity. File: gawk.info, Node: Updating ERRNO, Next: Requesting Values, Prev: Printing Messages, Up: Extension API Description -16.4.7 Updating 'ERRNO' +17.4.7 Updating 'ERRNO' ----------------------- The following functions allow you to update the 'ERRNO' variable: @@ -25047,7 +25488,7 @@ The following functions allow you to update the 'ERRNO' variable: File: gawk.info, Node: Requesting Values, Next: Accessing Parameters, Prev: Updating ERRNO, Up: Extension API Description -16.4.8 Requesting Values +17.4.8 Requesting Values ------------------------ All of the functions that return values from 'gawk' work in the same @@ -25057,7 +25498,7 @@ 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 16.1: table-value-types-returned. +summarized in *note Table 17.2: table-value-types-returned. Type of Actual Value -------------------------------------------------------------------------- @@ -25073,12 +25514,12 @@ Requested Array false false false false Array false Value false false false false false false cookie -Table 16.1: API value types returned +Table 17.2: 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 +17.4.9 Accessing and Updating Parameters ---------------------------------------- Two functions give you access to the arguments (parameters) passed to @@ -25090,7 +25531,7 @@ your extension function. They are: Fill in the 'awk_value_t' structure pointed to by 'result' with the 'count'th argument. Return true if the actual type matches 'wanted', and false otherwise. In the latter case, - 'result->val_type' indicates the actual type (*note Table 16.1: + 'result->val_type' indicates the actual type (*note Table 17.2: table-value-types-returned.). Counts are zero-based--the first argument is numbered zero, the second one, and so on. 'wanted' indicates the type of value expected. @@ -25104,7 +25545,7 @@ your extension function. They are: File: gawk.info, Node: Symbol Table Access, Next: Array Manipulation, Prev: Accessing Parameters, Up: Extension API Description -16.4.10 Symbol Table Access +17.4.10 Symbol Table Access --------------------------- Two sets of routines provide access to global variables, and one set @@ -25119,7 +25560,7 @@ allows you to create and release cached values. File: gawk.info, Node: Symbol table by name, Next: Symbol table by cookie, Up: Symbol Table Access -16.4.10.1 Variable Access and Update by Name +17.4.10.1 Variable Access and Update by Name ............................................ The following routines provide the ability to access and update global @@ -25136,7 +25577,19 @@ termed a "symbol table". The functions are as follows: regular C string. 'wanted' indicates the type of value expected. Return true if the actual type matches 'wanted', and false otherwise. In the latter case, 'result->val_type' indicates the - actual type (*note Table 16.1: table-value-types-returned.). + actual type (*note Table 17.2: table-value-types-returned.). + +'awk_bool_t sym_lookup_ns(const char *name,' +' const char *name_space,' +' awk_valtype_t wanted,' +' awk_value_t *result);' + This is like 'sym_lookup()', but the 'name_space' parameter allows + you to specify which namespace 'name' is part of. 'name_space' + cannot be 'NULL'. If it is '""' or '"awk"', then 'name' is + searched for in the default 'awk' namespace. + + Note that 'namespace' is a C++ keyword. For interoperability with + C++, you should avoid using that identifier in C code. 'awk_bool_t sym_update(const char *name, awk_value_t *value);' Update the variable named by the string 'name', which is a regular @@ -25148,14 +25601,30 @@ termed a "symbol table". The functions are as follows: an array. This routine cannot be used to update any of the predefined variables (such as 'ARGC' or 'NF'). +'awk_bool_t sym_update_ns(const char *name_space, const char *name, awk_value_t *value);' + This is like 'sym_update()', but the 'name_space' parameter allows + you to specify which namespace 'name' is part of. 'name_space' + cannot be 'NULL'. If it is '""' or '"awk', then 'name' is searched + for in the default 'awk' namespace. + An extension can look up the value of 'gawk''s special variables. However, with the exception of the 'PROCINFO' array, an extension cannot change any of those variables. + When searching for or updating variables outside the 'awk' namespace +(*note Namespaces::), function and variable names must be simple +identifiers.(1) In addition, namespace names and variable and function +names must follow the rules given in *note Naming Rules::. + + ---------- Footnotes ---------- + + (1) Allowing both namespace plus identifier and 'foo::bar' would have +been too confusing to document, and to code and test. + File: gawk.info, Node: Symbol table by cookie, Next: Cached values, Prev: Symbol table by name, Up: Symbol Table Access -16.4.10.2 Variable Access and Update by Cookie +17.4.10.2 Variable Access and Update by Cookie .............................................. A "scalar cookie" is an opaque handle that provides access to a global @@ -25269,7 +25738,7 @@ like this: File: gawk.info, Node: Cached values, Prev: Symbol table by cookie, Up: Symbol Table Access -16.4.10.3 Creating and Using Cached Values +17.4.10.3 Creating and Using Cached Values .......................................... The routines in this minor node allow you to create and release cached @@ -25367,7 +25836,7 @@ memory. File: gawk.info, Node: Array Manipulation, Next: Redirection API, Prev: Symbol Table Access, Up: Extension API Description -16.4.11 Array Manipulation +17.4.11 Array Manipulation -------------------------- The primary data structure(1) in 'awk' is the associative array (*note @@ -25394,7 +25863,7 @@ arrays of arrays (*note General Data Types::). File: gawk.info, Node: Array Data Types, Next: Array Functions, Up: Array Manipulation -16.4.11.1 Array Data Types +17.4.11.1 Array Data Types .......................... The data types associated with arrays are as follows: @@ -25461,7 +25930,7 @@ overuse this term. File: gawk.info, Node: Array Functions, Next: Flattening Arrays, Prev: Array Data Types, Up: Array Manipulation -16.4.11.2 Array Functions +17.4.11.2 Array Functions ......................... The following functions relate to individual array elements: @@ -25479,7 +25948,7 @@ The following functions relate to individual array elements: value of the element whose index is 'index'. 'wanted' specifies the type of value you wish to retrieve. Return false if 'wanted' does not match the actual type or if 'index' is not in the array - (*note Table 16.1: table-value-types-returned.). + (*note Table 17.2: table-value-types-returned.). The value for 'index' can be numeric, in which case 'gawk' converts it to a string. Using nonintegral values is possible, but requires @@ -25551,7 +26020,7 @@ The following functions relate to individual array elements: File: gawk.info, Node: Flattening Arrays, Next: Creating Arrays, Prev: Array Functions, Up: Array Manipulation -16.4.11.3 Working With All The Elements of an Array +17.4.11.3 Working With All The Elements of an Array ................................................... To "flatten" an array is to create a structure that represents the full @@ -25725,7 +26194,7 @@ return value to success, and returns: File: gawk.info, Node: Creating Arrays, Prev: Flattening Arrays, Up: Array Manipulation -16.4.11.4 How To Create and Populate Arrays +17.4.11.4 How To Create and Populate Arrays ........................................... Besides working with arrays created by 'awk' code, you can create arrays @@ -25864,7 +26333,7 @@ environment variable.) File: gawk.info, Node: Redirection API, Next: Extension API Variables, Prev: Array Manipulation, Up: Extension API Description -16.4.12 Accessing and Manipulating Redirections +17.4.12 Accessing and Manipulating Redirections ----------------------------------------------- The following function allows extensions to access and manipulate @@ -25934,7 +26403,7 @@ I/O multiplexing and a socket library. File: gawk.info, Node: Extension API Variables, Next: Extension API Boilerplate, Prev: Redirection API, Up: Extension API Description -16.4.13 API Variables +17.4.13 API Variables --------------------- The API provides two sets of variables. The first provides information @@ -25952,7 +26421,7 @@ information about how 'gawk' was invoked. File: gawk.info, Node: Extension Versioning, Next: Extension GMP/MPFR Versioning, Up: Extension API Variables -16.4.13.1 API Version Constants and Variables +17.4.13.1 API Version Constants and Variables ............................................. The API provides both a "major" and a "minor" version number. The API @@ -25965,7 +26434,7 @@ API Version C Preprocessor Define enum constant Major 'gawk_api_major_version' 'GAWK_API_MAJOR_VERSION' Minor 'gawk_api_minor_version' 'GAWK_API_MINOR_VERSION' -Table 16.2: gawk API version constants +Table 17.3: gawk API version constants The minor version increases when new functions are added to the API. Such new functions are always added to the end of the API 'struct'. @@ -26004,7 +26473,7 @@ Boilerplate::). File: gawk.info, Node: Extension GMP/MPFR Versioning, Next: Extension API Informational Variables, Prev: Extension Versioning, Up: Extension API Variables -16.4.13.2 GMP and MPFR Version Information +17.4.13.2 GMP and MPFR Version Information .......................................... The API also includes information about the versions of GMP and MPFR @@ -26046,7 +26515,7 @@ match those of 'gawk' with the following macro: File: gawk.info, Node: Extension API Informational Variables, Prev: Extension GMP/MPFR Versioning, Up: Extension API Variables -16.4.13.3 Informational Variables +17.4.13.3 Informational Variables ................................. The API provides access to several variables that describe whether the @@ -26081,7 +26550,7 @@ change during execution. File: gawk.info, Node: Extension API Boilerplate, Next: Changes from API V1, Prev: Extension API Variables, Up: Extension API Description -16.4.14 Boilerplate Code +17.4.14 Boilerplate Code ------------------------ As mentioned earlier (*note Extension Mechanism Outline::), the function @@ -26185,7 +26654,7 @@ does the following: File: gawk.info, Node: Changes from API V1, Prev: Extension API Boilerplate, Up: Extension API Description -16.4.15 Changes From Version 1 of the API +17.4.15 Changes From Version 1 of the API ----------------------------------------- The current API is _not_ binary compatible with version 1 of the API. @@ -26227,7 +26696,7 @@ version 2 of the API: File: gawk.info, Node: Finding Extensions, Next: Extension Example, Prev: Extension API Description, Up: Dynamic Extensions -16.5 How 'gawk' Finds Extensions +17.5 How 'gawk' Finds Extensions ================================ Compiled extensions have to be installed in a directory where 'gawk' can @@ -26239,7 +26708,7 @@ compiled extensions. *Note AWKLIBPATH Variable:: for more information. File: gawk.info, Node: Extension Example, Next: Extension Samples, Prev: Finding Extensions, Up: Dynamic Extensions -16.6 Example: Some File Functions +17.6 Example: Some File Functions ================================= No matter where you go, there you are. @@ -26260,7 +26729,7 @@ in an extension. File: gawk.info, Node: Internal File Description, Next: Internal File Ops, Up: Extension Example -16.6.1 Using 'chdir()' and 'stat()' +17.6.1 Using 'chdir()' and 'stat()' ----------------------------------- This minor node shows how to use the new functions at the 'awk' level @@ -26390,7 +26859,7 @@ Elements::): File: gawk.info, Node: Internal File Ops, Next: Using Internal File Ops, Prev: Internal File Description, Up: Extension Example -16.6.2 C Code for 'chdir()' and 'stat()' +17.6.2 C Code for 'chdir()' and 'stat()' ---------------------------------------- Here is the C code for these extensions.(1) @@ -26733,7 +27202,7 @@ version. File: gawk.info, Node: Using Internal File Ops, Prev: Internal File Ops, Up: Extension Example -16.6.3 Integrating the Extensions +17.6.3 Integrating the Extensions --------------------------------- Now that the code is written, it must be possible to add it at runtime @@ -26814,7 +27283,7 @@ file. *Note gawkextlib:: for Internet links to the tools. File: gawk.info, Node: Extension Samples, Next: gawkextlib, Prev: Extension Example, Up: Dynamic Extensions -16.7 The Sample Extensions in the 'gawk' Distribution +17.7 The Sample Extensions in the 'gawk' Distribution ===================================================== This minor node provides a brief overview of the sample extensions that @@ -26844,7 +27313,7 @@ the extension API. File: gawk.info, Node: Extension Sample File Functions, Next: Extension Sample Fnmatch, Up: Extension Samples -16.7.1 File-Related Functions +17.7.1 File-Related Functions ----------------------------- The 'filefuncs' extension provides three different functions, as @@ -27014,7 +27483,7 @@ the 'fts()' extension function. File: gawk.info, Node: Extension Sample Fnmatch, Next: Extension Sample Fork, Prev: Extension Sample File Functions, Up: Extension Samples -16.7.2 Interface to 'fnmatch()' +17.7.2 Interface to 'fnmatch()' ------------------------------- This extension provides an interface to the C library 'fnmatch()' @@ -27065,7 +27534,7 @@ Array element Corresponding flag defined by 'fnmatch()' File: gawk.info, Node: Extension Sample Fork, Next: Extension Sample Inplace, Prev: Extension Sample Fnmatch, Up: Extension Samples -16.7.3 Interface to 'fork()', 'wait()', and 'waitpid()' +17.7.3 Interface to 'fork()', 'wait()', and 'waitpid()' ------------------------------------------------------- The 'fork' extension adds three functions, as follows: @@ -27102,19 +27571,21 @@ The 'fork' extension adds three functions, as follows: File: gawk.info, Node: Extension Sample Inplace, Next: Extension Sample Ord, Prev: Extension Sample Fork, Up: Extension Samples -16.7.4 Enabling In-Place File Editing +17.7.4 Enabling In-Place File Editing ------------------------------------- The 'inplace' extension emulates GNU 'sed''s '-i' option, which performs "in-place" editing of each input file. It uses the bundled -'inplace.awk' include file to invoke the extension properly: +'inplace.awk' include file to invoke the extension properly. This +extension makes use of the namespace facility to place all the variables +and functions in the 'inplace' namespace (*note Namespaces::): # inplace --- load and invoke the inplace extension. @load "inplace" - # Please set INPLACE_SUFFIX to make a backup copy. For example, you may - # want to set INPLACE_SUFFIX to .bak on the command line or in a BEGIN rule. + # Please set inplace::suffix to make a backup copy. For example, you may + # want to set inplace::suffix to .bak on the command line or in a BEGIN rule. # By default, each filename on the command line will be edited inplace. # But you can selectively disable this by adding an inplace=0 argument @@ -27122,44 +27593,46 @@ The 'inplace' extension emulates GNU 'sed''s '-i' option, which performs # reenable it later on the commandline by putting inplace=1 before files # that you wish to be subject to inplace editing. - # N.B. We call inplace_end() in the BEGINFILE and END rules so that any + # N.B. We call inplace::end() in the BEGINFILE and END rules so that any # actions in an ENDFILE rule will be redirected as expected. + @namespace "inplace" + BEGIN { - inplace = 1 # enabled by default + enable = 1 # enabled by default } BEGINFILE { - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) - if (inplace) - inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) + if (enable) + begin(filename = FILENAME, suffix) else - _inplace_filename = "" + filename = "" } END { - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) } For each regular file that is processed, the extension redirects standard output to a temporary file configured to have the same owner and permissions as the original. After the file has been processed, the extension restores standard output to its original destination. If -'INPLACE_SUFFIX' is not an empty string, the original file is linked to +'inplace::suffix' is not an empty string, the original file is linked to a backup file name created by appending that suffix. Finally, the temporary file is renamed to the original file name. Note that the use of this feature can be controlled by placing -'inplace=0' on the command-line prior to listing files that should not -be processed this way. You can reenable inplace editing by adding an -'inplace=1' argument prior to files that should be subject to inplace -editing. +'inplace::enable=0' on the command-line prior to listing files that +should not be processed this way. You can reenable inplace editing by +adding an 'inplace::enable=1' argument prior to files that should be +subject to inplace editing. - The '_inplace_filename' variable serves to keep track of the current -filename so as to not invoke 'inplace_end()' before processing the first -file. + The 'inplace::filename' variable serves to keep track of the current +filename so as to not invoke 'inplace::end()' before processing the +first file. If any error occurs, the extension issues a fatal error to terminate processing immediately without damaging the original file. @@ -27170,7 +27643,7 @@ processing immediately without damaging the original file. To keep a backup copy of the original files, try this: - $ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") } + $ gawk -i inplace -v inplace::suffix=.bak '{ gsub(/foo/, "bar") } > { print }' file1 file2 file3 Please note that, while the extension does attempt to preserve @@ -27183,7 +27656,7 @@ signal is received, a temporary file may be left behind. File: gawk.info, Node: Extension Sample Ord, Next: Extension Sample Readdir, Prev: Extension Sample Inplace, Up: Extension Samples -16.7.5 Character and Numeric values: 'ord()' and 'chr()' +17.7.5 Character and Numeric values: 'ord()' and 'chr()' -------------------------------------------------------- The 'ordchr' extension adds two functions, named 'ord()' and 'chr()', as @@ -27210,7 +27683,7 @@ same name. Here is an example: File: gawk.info, Node: Extension Sample Readdir, Next: Extension Sample Revout, Prev: Extension Sample Ord, Up: Extension Samples -16.7.6 Reading Directories +17.7.6 Reading Directories -------------------------- The 'readdir' extension adds an input parser for directories. The usage @@ -27227,7 +27700,7 @@ 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 and their corresponding -file types are shown in *note Table 16.3: table-readdir-file-types. +file types are shown in *note Table 17.4: table-readdir-file-types. Letter File type -------------------------------------------------------------------------- @@ -27240,7 +27713,7 @@ Letter File type 's' Socket 'u' Anything else (unknown) -Table 16.3: File types returned by the 'readdir' extension +Table 17.4: File types returned by the 'readdir' extension On systems without the file type information, the third field is always 'u'. @@ -27260,7 +27733,7 @@ always 'u'. File: gawk.info, Node: Extension Sample Revout, Next: Extension Sample Rev2way, Prev: Extension Sample Readdir, Up: Extension Samples -16.7.7 Reversing Output +17.7.7 Reversing Output ----------------------- The 'revoutput' extension adds a simple output wrapper that reverses the @@ -27280,7 +27753,7 @@ unwary. Here is an example: File: gawk.info, Node: Extension Sample Rev2way, Next: Extension Sample Read write array, Prev: Extension Sample Revout, Up: Extension Samples -16.7.8 Two-Way I/O Example +17.7.8 Two-Way I/O Example -------------------------- The 'revtwoway' extension adds a simple two-way processor that reverses @@ -27304,7 +27777,7 @@ to use it: File: gawk.info, Node: Extension Sample Read write array, Next: Extension Sample Readfile, Prev: Extension Sample Rev2way, Up: Extension Samples -16.7.9 Dumping and Restoring an Array +17.7.9 Dumping and Restoring an Array ------------------------------------- The 'rwarray' extension adds two functions, named 'writea()' and @@ -27351,7 +27824,7 @@ on systems with a different one, but this has not been tried. 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 +17.7.10 Reading an Entire File ------------------------------ The 'readfile' extension adds a single function named 'readfile()', and @@ -27384,7 +27857,7 @@ an input parser: File: gawk.info, Node: Extension Sample Time, Next: Extension Sample API Tests, Prev: Extension Sample Readfile, Up: Extension Samples -16.7.11 Extension Time Functions +17.7.11 Extension Time Functions -------------------------------- The 'time' extension adds two functions, named 'gettimeofday()' and @@ -27415,7 +27888,7 @@ The 'time' extension adds two functions, named 'gettimeofday()' and File: gawk.info, Node: Extension Sample API Tests, Prev: Extension Sample Time, Up: Extension Samples -16.7.12 API Tests +17.7.12 API Tests ----------------- The 'testext' extension exercises parts of the extension API that are @@ -27427,7 +27900,7 @@ 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 +17.8 The 'gawkextlib' Project ============================= The 'gawkextlib' (https://sourceforge.net/projects/gawkextlib/) project @@ -27496,7 +27969,7 @@ project's website for more information. File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: gawkextlib, Up: Dynamic Extensions -16.9 Summary +17.9 Summary ============ * You can write extensions (sometimes called plug-ins) for 'gawk' in @@ -27584,7 +28057,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga File: gawk.info, Node: Extension Exercises, Prev: Extension summary, Up: Dynamic Extensions -16.10 Exercises +17.10 Exercises =============== 1. Add functions to implement system calls such as 'chown()', @@ -27605,12 +28078,7 @@ File: gawk.info, Node: Extension Exercises, Prev: Extension summary, Up: Dyna writing the prompt? Which reading mechanism should you replace, the one to get a record, or the one to read raw bytes? - 3. (Hard.) How would you provide namespaces in 'gawk', so that the - names of functions in different extensions don't conflict with each - other? If you come up with a really good scheme, contact the - 'gawk' maintainer to tell him about it. - - 4. Write a wrapper script that provides an interface similar to 'sed + 3. Write a wrapper script that provides an interface similar to 'sed -i' for the "inplace" extension presented in *note Extension Sample Inplace::. @@ -28441,6 +28909,11 @@ POSIX 'awk', in the order they were added to 'gawk'. * Support for GNU/Linux on Alpha was removed. + Version 5.0 added the following features: + + * The 'PROCINFO["platform"]' array element, which allows you to write + code that takes the operating system / platform into account. + File: gawk.info, Node: Common Extensions, Next: Ranges and Locales, Prev: Feature History, Up: Language History @@ -29206,10 +29679,6 @@ command line when compiling 'gawk' from scratch, including: possible to keep extensions for different API versions on the same system without their conflicting with one another. -'--with-whiny-user-strftime' - Force use of the included version of the C 'strftime()' function - for deficient systems. - Use the command './configure --help' to see the full list of options supplied by 'configure'. @@ -29375,6 +29844,12 @@ accomplished by using an appropriate '-v BINMODE=N' option on the command line. 'BINMODE' is set at the time a file or pipe is opened and cannot be changed midstream. + On POSIX-compatible systems, this variable's value has no effect. +Thus, if you think your program will run on multiple different systems +and that you may need to use 'BINMODE', you should simply set it (in the +program or on the command line) unconditionally, and not worry about the +operating system on which your program is running. + The name 'BINMODE' was chosen to match 'mawk' (*note Other Versions::). 'mawk' and 'gawk' handle 'BINMODE' similarly; however, 'mawk' adds a '-W BINMODE=N' option and an environment variable that can @@ -33076,13 +33551,13 @@ Index * - (hyphen), -- operator <1>: Precedence. (line 45) * - (hyphen), -= operator: Assignment Ops. (line 129) * - (hyphen), -= operator <1>: Precedence. (line 94) -* - (hyphen), file names beginning with: Options. (line 60) +* - (hyphen), file names beginning with: Options. (line 64) * - (hyphen), in bracket expressions: Bracket Expressions. (line 25) -* --assign option: Options. (line 32) -* --bignum option: Options. (line 217) -* --characters-as-bytes option: Options. (line 69) -* --copyright option: Options. (line 89) -* --debug option: Options. (line 108) +* --assign option: Options. (line 36) +* --bignum option: Options. (line 229) +* --characters-as-bytes option: Options. (line 73) +* --copyright option: Options. (line 93) +* --debug option: Options. (line 112) * --disable-extensions configuration option: Additional Configuration Options. (line 9) * --disable-lint configuration option: Additional Configuration Options. @@ -33091,83 +33566,81 @@ Index (line 32) * --disable-nls configuration option: Additional Configuration Options. (line 37) -* --dump-variables option: Options. (line 94) +* --dump-variables option: Options. (line 98) * --dump-variables option, using for library functions: Library Names. (line 45) * --enable-versioned-extension-dir configuration option: Additional Configuration Options. (line 42) -* --exec option: Options. (line 139) +* --exec option: Options. (line 147) * --field-separator option: Options. (line 21) * --file option: Options. (line 25) -* --gen-pot option: Options. (line 161) +* --gen-pot option: Options. (line 169) * --gen-pot option <1>: String Extraction. (line 6) * --gen-pot option <2>: String Extraction. (line 6) -* --help option: Options. (line 168) -* --include option: Options. (line 173) +* --help option: Options. (line 176) +* --include option: Options. (line 181) * --lint option: Command Line. (line 20) -* --lint option <1>: Options. (line 198) -* --lint-old option: Options. (line 312) -* --load option: Options. (line 186) -* --no-optimize option: Options. (line 298) -* --non-decimal-data option: Options. (line 223) +* --lint option <1>: Options. (line 210) +* --lint-old option: Options. (line 324) +* --load option: Options. (line 198) +* --no-optimize option: Options. (line 310) +* --non-decimal-data option: Options. (line 235) * --non-decimal-data option <1>: Nondecimal Data. (line 6) * --non-decimal-data option, strtonum() function and: Nondecimal Data. (line 35) -* --optimize option: Options. (line 248) -* --posix option: Options. (line 270) -* --posix option, --traditional option and: Options. (line 285) -* --pretty-print option: Options. (line 237) -* --profile option: Options. (line 258) +* --optimize option: Options. (line 260) +* --posix option: Options. (line 282) +* --posix option, --traditional option and: Options. (line 297) +* --pretty-print option: Options. (line 249) +* --profile option: Options. (line 270) * --profile option <1>: Profiling. (line 12) -* --re-interval option: Options. (line 291) -* --sandbox option: Options. (line 303) +* --re-interval option: Options. (line 303) +* --sandbox option: Options. (line 315) * --sandbox option, disabling system() function: I/O Functions. (line 128) * --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 82) -* --traditional option, --posix option and: Options. (line 285) -* --use-lc-numeric option: Options. (line 232) -* --version option: Options. (line 317) -* --with-whiny-user-strftime configuration option: Additional Configuration Options. - (line 48) -* -b option: Options. (line 69) -* -c option: Options. (line 82) -* -C option: Options. (line 89) -* -d option: Options. (line 94) -* -D option: Options. (line 108) -* -e option: Options. (line 117) -* -E option: Options. (line 139) -* -e option <1>: Options. (line 353) +* --source option: Options. (line 121) +* --traditional option: Options. (line 86) +* --traditional option, --posix option and: Options. (line 297) +* --use-lc-numeric option: Options. (line 244) +* --version option: Options. (line 329) +* -b option: Options. (line 73) +* -c option: Options. (line 86) +* -C option: Options. (line 93) +* -d option: Options. (line 98) +* -D option: Options. (line 112) +* -e option: Options. (line 121) +* -E option: Options. (line 147) +* -e option <1>: Options. (line 365) * -f option: Long. (line 12) * -F option: Options. (line 21) * -f option <1>: Options. (line 25) -* -F option, -Ft sets FS to TAB: Options. (line 325) +* -F option, -Ft sets FS to TAB: Options. (line 337) * -F option, command-line: Command Line Field Separator. (line 6) -* -f option, multiple uses: Options. (line 330) -* -g option: Options. (line 161) -* -h option: Options. (line 168) -* -i option: Options. (line 173) -* -l option: Options. (line 186) -* -l option <1>: Options. (line 198) -* -L option: Options. (line 312) -* -M option: Options. (line 217) -* -n option: Options. (line 223) -* -N option: Options. (line 232) -* -o option: Options. (line 237) -* -O option: Options. (line 248) -* -p option: Options. (line 258) -* -P option: Options. (line 270) -* -r option: Options. (line 291) -* -s option: Options. (line 298) -* -S option: Options. (line 303) -* -v option: Options. (line 32) -* -V option: Options. (line 317) +* -f option, multiple uses: Options. (line 342) +* -g option: Options. (line 169) +* -h option: Options. (line 176) +* -i option: Options. (line 181) +* -l option: Options. (line 198) +* -l option <1>: Options. (line 210) +* -L option: Options. (line 324) +* -M option: Options. (line 229) +* -n option: Options. (line 235) +* -N option: Options. (line 244) +* -o option: Options. (line 249) +* -O option: Options. (line 260) +* -p option: Options. (line 270) +* -P option: Options. (line 282) +* -r option: Options. (line 303) +* -s option: Options. (line 310) +* -S option: Options. (line 315) +* -v option: Options. (line 36) +* -V option: Options. (line 329) * -v option <1>: Assignment Options. (line 12) -* -W option: Options. (line 47) +* -W option: Options. (line 51) * . (period), regexp operator: Regexp Operators. (line 44) * .gmo files: Explaining gettext. (line 42) * .gmo files, specifying directory of: Explaining gettext. (line 54) @@ -33191,6 +33664,7 @@ Index * /inet4/... special files (gawk): TCP/IP Networking. (line 6) * /inet6/... special files (gawk): TCP/IP Networking. (line 6) * : (colon), ?: operator: Precedence. (line 91) +* ::, namespace separator: Qualified Names. (line 6) * ; (semicolon), AWKPATH variable and: PC Using. (line 13) * ; (semicolon), separating rules: Statements/Lines. (line 90) * ; (semicolon), separating statements in actions: Statements/Lines. @@ -33227,6 +33701,10 @@ Index * @include directive: Include Files. (line 8) * @load directive: Loading Shared Libraries. (line 8) +* @namespace directive: Changing The Namespace. + (line 6) +* @namespace, no effect on BEGIN BEGINFILE, END, and ENDFILE: Changing The Namespace. + (line 37) * [] (square brackets), regexp operator: Regexp Operators. (line 56) * \ (backslash): Comments. (line 50) * \ (backslash), as field separator: Command Line Field Separator. @@ -33469,9 +33947,14 @@ Index * atan2: Numeric Functions. (line 12) * automatic displays, in debugger: Debugger Info. (line 24) * awf (amazingly workable formatter) program: Glossary. (line 23) -* awk debugging, enabling: Options. (line 108) +* awk debugging, enabling: Options. (line 112) * awk language, POSIX version: Assignment Ops. (line 138) -* awk profiling, enabling: Options. (line 258) +* awk namespace: Default Namespace. (line 6) +* awk namespace, identifier name storage: Internal Name Management. + (line 6) +* awk namespace, use for indirect function calls: Internal Name Management. + (line 6) +* awk profiling, enabling: Options. (line 270) * awk programs: Getting Started. (line 12) * awk programs <1>: Executable Scripts. (line 6) * awk programs <2>: Two Rules. (line 6) @@ -33485,8 +33968,8 @@ Index * awk programs, lengthy: Long. (line 6) * awk programs, lengthy, assertions: Assert Function. (line 6) * awk programs, location of: Options. (line 25) -* awk programs, location of <1>: Options. (line 139) -* awk programs, location of <2>: Options. (line 173) +* awk programs, location of <1>: Options. (line 147) +* awk programs, location of <2>: Options. (line 181) * awk programs, one-line examples: Very Simple. (line 46) * awk programs, profiling: Profiling. (line 6) * awk programs, running: Running gawk. (line 6) @@ -33528,7 +34011,7 @@ Index * AWKPATH environment variable <1>: PC Using. (line 13) * awkprof.out file: Profiling. (line 6) * awksed.awk program: Simple Sed. (line 25) -* awkvars.out file: Options. (line 94) +* awkvars.out file: Options. (line 98) * b debugger command (alias for break): Breakpoint Control. (line 11) * backslash (\): Comments. (line 50) * backslash (\), as field separator: Command Line Field Separator. @@ -33603,10 +34086,14 @@ Index * BEGIN pattern, pwcat program: Passwd Functions. (line 143) * BEGIN pattern, running awk programs and: Cut Program. (line 63) * BEGIN pattern, TEXTDOMAIN variable and: Programmer i18n. (line 60) +* BEGIN, execution order not affected by @namespace: Changing The Namespace. + (line 37) * BEGINFILE pattern: BEGINFILE/ENDFILE. (line 6) * BEGINFILE pattern, Boolean patterns and: Expression Patterns. (line 70) * beginfile() user-defined function: Filetrans Function. (line 62) +* BEGINFILE, execution order not affected by @namespace: Changing The Namespace. + (line 37) * Bentley, Jon: Glossary. (line 204) * Benzinger, Michael: Contributors. (line 100) * Berry, Karl: Acknowledgments. (line 33) @@ -33730,7 +34217,7 @@ Index * case sensitivity, regexps and: Case-sensitivity. (line 6) * case sensitivity, regexps and <1>: User-modified. (line 79) * case sensitivity, string comparisons and: User-modified. (line 79) -* CGI, awk scripts for: Options. (line 139) +* CGI, awk scripts for: Options. (line 147) * character classes, See bracket expressions: Regexp Operators. (line 56) * character lists in regular expressions: Bracket Expressions. @@ -33790,7 +34277,7 @@ Index * command line, invoking awk from: Command Line. (line 6) * command line, option -f: Long. (line 12) * command line, options: Options. (line 6) -* command line, options, end of: Options. (line 55) +* command line, options, end of: Options. (line 59) * command line, variables, assigning on: Assignment Options. (line 6) * command-line options, processing: Getopt Function. (line 6) * command-line options, string extraction: String Extraction. (line 6) @@ -33826,7 +34313,7 @@ Index (line 59) * compatibility mode (gawk), octal numbers: Nondecimal-numbers. (line 59) -* compatibility mode (gawk), specifying: Options. (line 82) +* compatibility mode (gawk), specifying: Options. (line 86) * compiled programs: Basic High Level. (line 13) * compiled programs <1>: Glossary. (line 216) * compiling gawk for Cygwin: Cygwin. (line 6) @@ -33834,6 +34321,8 @@ Index * compiling gawk for VMS: VMS Compilation. (line 6) * compl: Bitwise Functions. (line 44) * complement, bitwise: Bitwise Functions. (line 25) +* component name: Qualified Names. (line 6) +* component names, naming rules: Naming Rules. (line 6) * compound statements, control statements and: Statements. (line 10) * concatenating: Concatenation. (line 9) * condition debugger command: Breakpoint Control. (line 54) @@ -33848,8 +34337,6 @@ Index (line 37) * configuration option, --enable-versioned-extension-dir: Additional Configuration Options. (line 42) -* configuration option, --with-whiny-user-strftime: Additional Configuration Options. - (line 48) * configuration options, gawk: Additional Configuration Options. (line 6) * constant regexps: Regexp Usage. (line 57) @@ -33888,11 +34375,13 @@ Index * cosine: Numeric Functions. (line 16) * counting: Wc Program. (line 6) * csh utility: Statements/Lines. (line 43) -* csh utility, POSIXLY_CORRECT environment variable: Options. (line 371) +* csh utility, POSIXLY_CORRECT environment variable: Options. (line 383) * csh utility, |& operator, comparison with: Two-way I/O. (line 27) * ctime() user-defined function: Function Example. (line 74) * Curreli, Marco: Contributors. (line 147) * currency symbols, localization: Explaining gettext. (line 104) +* current namespace, pushing and popping: Changing The Namespace. + (line 29) * current system time: Time Functions. (line 68) * custom.h file: Configuration Philosophy. (line 30) @@ -33926,7 +34415,7 @@ Index * dark corner, field separators: Full Line Fields. (line 22) * dark corner, FILENAME variable: Getline Notes. (line 19) * dark corner, FILENAME variable <1>: Auto-set. (line 108) -* dark corner, FNR/NR variables: Auto-set. (line 389) +* dark corner, FNR/NR variables: Auto-set. (line 409) * dark corner, format-control characters: Control Letters. (line 33) * dark corner, format-control characters <1>: Control Letters. (line 108) @@ -34087,6 +34576,8 @@ Index * debugger, history size: Debugger Info. (line 65) * debugger, how to start: Debugger Invocation. (line 6) * debugger, instruction tracing: Debugger Info. (line 90) +* debugger, interaction with namespaces: Namespace And Features. + (line 17) * debugger, limitations: Limitations. (line 6) * debugger, n command: Finding The Bug. (line 105) * debugger, next command: Finding The Bug. (line 105) @@ -34109,7 +34600,7 @@ Index * debugging gawk, bug reports: Bugs. (line 9) * debugging, example session: Sample Debugging Session. (line 6) -* decimal point character, locale specific: Options. (line 282) +* decimal point character, locale specific: Options. (line 294) * decrement operators: Increment Ops. (line 35) * default keyword: Switch Statement. (line 6) * Deifik, Scott: Acknowledgments. (line 60) @@ -34194,7 +34685,7 @@ Index (line 58) * differences in awk and gawk, RS/RT variables <2>: Multiple Line. (line 130) -* differences in awk and gawk, RS/RT variables <3>: Auto-set. (line 327) +* differences in awk and gawk, RS/RT variables <3>: Auto-set. (line 348) * differences in awk and gawk, single-character fields: Single Character Fields. (line 6) * differences in awk and gawk, split() function: String Functions. @@ -34203,7 +34694,7 @@ Index * differences in awk and gawk, strings <1>: Scalar Constants. (line 53) * differences in awk and gawk, strings, storing: gawk split records. (line 76) -* differences in awk and gawk, SYMTAB variable: Auto-set. (line 331) +* differences in awk and gawk, SYMTAB variable: Auto-set. (line 352) * differences in awk and gawk, TEXTDOMAIN variable: User-modified. (line 155) * differences in awk and gawk, trunc-mod operation: Arithmetic Ops. @@ -34236,11 +34727,11 @@ Index * down debugger command: Execution Stack. (line 23) * Drepper, Ulrich: Acknowledgments. (line 52) * Duman, Patrice: Acknowledgments. (line 75) -* dump all variables of a program: Options. (line 94) +* dump all variables of a program: Options. (line 98) * dump debugger command: Miscellaneous Debugger Commands. (line 9) * dupword.awk program: Dupword Program. (line 31) -* dynamic profiling: Profiling. (line 177) +* dynamic profiling: Profiling. (line 179) * dynamically loaded extensions: Dynamic Extensions. (line 6) * e debugger command (alias for enable): Breakpoint Control. (line 73) * EBCDIC: Ordinal Functions. (line 45) @@ -34282,9 +34773,13 @@ Index * END pattern, operators and: Using BEGIN/END. (line 17) * END pattern, print statement and: I/O And BEGIN/END. (line 15) * END pattern, profiling and: Profiling. (line 62) +* END, execution order not affected by @namespace: Changing The Namespace. + (line 37) * ENDFILE pattern: BEGINFILE/ENDFILE. (line 6) * ENDFILE pattern, Boolean patterns and: Expression Patterns. (line 70) * endfile() user-defined function: Filetrans Function. (line 62) +* ENDFILE, execution order not affected by @namespace: Changing The Namespace. + (line 37) * endgrent() function (C library): Group Functions. (line 213) * endgrent() user-defined function: Group Functions. (line 216) * endpwent() function (C library): Passwd Functions. (line 208) @@ -34369,7 +34864,9 @@ Index (line 6) * extension API version: Extension Versioning. (line 6) -* extension API, version number: Auto-set. (line 266) +* extension API, interaction with namespaces: Namespace And Features. + (line 22) +* extension API, version number: Auto-set. (line 287) * extension example: Extension Example. (line 6) * extension registration: Registration Functions. (line 6) @@ -34474,7 +34971,7 @@ Index * files, /inet6/... (gawk): TCP/IP Networking. (line 6) * files, awk programs in: Long. (line 6) * files, awkprof.out: Profiling. (line 6) -* files, awkvars.out: Options. (line 94) +* files, awkvars.out: Options. (line 98) * files, closing: I/O Functions. (line 10) * files, descriptors, See file descriptors: Special FD. (line 6) * files, group: Group Functions. (line 6) @@ -34501,7 +34998,7 @@ Index * files, portable object template: Explaining gettext. (line 31) * files, portable object, converting to message object files: I18N Example. (line 80) -* files, portable object, generating: Options. (line 161) +* files, portable object, generating: Options. (line 169) * files, processing, ARGIND variable and: Auto-set. (line 50) * files, reading: Rewind Function. (line 6) * files, reading, multiline records: Multiple Line. (line 6) @@ -34533,7 +35030,7 @@ Index (line 12) * FNR variable: Records. (line 6) * FNR variable <1>: Auto-set. (line 118) -* FNR variable, changing: Auto-set. (line 389) +* FNR variable, changing: Auto-set. (line 409) * for statement: For Statement. (line 6) * for statement, looping over arrays: Scanning an Array. (line 20) * fork() extension function: Extension Sample Fork. @@ -34575,7 +35072,7 @@ Index * FS variable, running awk programs and: Cut Program. (line 63) * FS variable, setting from command line: Command Line Field Separator. (line 6) -* FS variable, TAB character as: Options. (line 279) +* FS variable, TAB character as: Options. (line 291) * FS, containing ^: Regexp Field Splitting. (line 59) * FS, in multiline records: Multiple Line. (line 41) @@ -34636,8 +35133,8 @@ Index * G., Daniel Richard: Acknowledgments. (line 60) * G., Daniel Richard <1>: Maintainers. (line 14) * Garfinkle, Scott: Contributors. (line 35) -* gawk program, dynamic profiling: Profiling. (line 177) -* gawk version: Auto-set. (line 241) +* gawk program, dynamic profiling: Profiling. (line 179) +* gawk version: Auto-set. (line 262) * gawk, ARGIND variable in: Other Arguments. (line 15) * gawk, awk and: Preface. (line 21) * gawk, awk and <1>: This Manual. (line 14) @@ -34661,7 +35158,7 @@ Index * gawk, ERRNO variable in <3>: Auto-set. (line 87) * gawk, ERRNO variable in <4>: TCP/IP Networking. (line 54) * gawk, escape sequences: Escape Sequences. (line 121) -* gawk, extensions, disabling: Options. (line 270) +* gawk, extensions, disabling: Options. (line 282) * gawk, features, adding: Adding Code. (line 6) * gawk, features, advanced: Advanced Features. (line 6) * gawk, field separators and: User-modified. (line 74) @@ -34714,17 +35211,17 @@ Index * gawk, RT variable in: awk split records. (line 131) * gawk, RT variable in <1>: gawk split records. (line 58) * gawk, RT variable in <2>: Multiple Line. (line 130) -* gawk, RT variable in <3>: Auto-set. (line 327) +* gawk, RT variable in <3>: Auto-set. (line 348) * gawk, See Also awk: Preface. (line 34) * gawk, source code, obtaining: Getting. (line 6) * gawk, splitting fields and: Testing field creation. (line 6) * gawk, string-translation functions: I18N Functions. (line 6) -* gawk, SYMTAB array in: Auto-set. (line 331) +* gawk, SYMTAB array in: Auto-set. (line 352) * gawk, TEXTDOMAIN variable in: User-modified. (line 155) * gawk, timestamps: Time Functions. (line 6) * gawk, uses for: Preface. (line 34) -* gawk, versions of, information about, printing: Options. (line 317) +* gawk, versions of, information about, printing: Options. (line 329) * gawk, VMS version of: VMS Installation. (line 6) * gawk, word-boundary operator: GNU Regexp Operators. (line 66) @@ -34803,7 +35300,7 @@ Index * GNU Lesser General Public License: Glossary. (line 489) * GNU long options: Command Line. (line 13) * GNU long options <1>: Options. (line 6) -* GNU long options, printing list of: Options. (line 168) +* GNU long options, printing list of: Options. (line 176) * GNU Project: Manual History. (line 11) * GNU Project <1>: Glossary. (line 403) * GNU/Linux: Manual History. (line 28) @@ -34814,7 +35311,7 @@ Index * Gordon, Assaf: Contributors. (line 108) * GPL (General Public License): Manual History. (line 11) * GPL (General Public License) <1>: Glossary. (line 394) -* GPL (General Public License), printing: Options. (line 89) +* GPL (General Public License), printing: Options. (line 93) * grcat program: Group Functions. (line 16) * Grigera, Juan: Contributors. (line 58) * group database, reading: Group Functions. (line 6) @@ -34840,18 +35337,18 @@ Index * help debugger command: Miscellaneous Debugger Commands. (line 67) * hexadecimal numbers: Nondecimal-numbers. (line 6) -* hexadecimal values, enabling interpretation of: Options. (line 223) +* hexadecimal values, enabling interpretation of: Options. (line 235) * 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 209) +* HUP signal, for dynamic profiling: Profiling. (line 211) * hyphen (-), - operator: Precedence. (line 51) * hyphen (-), - operator <1>: Precedence. (line 57) * hyphen (-), -- operator: Increment Ops. (line 48) * hyphen (-), -- operator <1>: Precedence. (line 45) * hyphen (-), -= operator: Assignment Ops. (line 129) * hyphen (-), -= operator <1>: Precedence. (line 94) -* hyphen (-), file names beginning with: Options. (line 60) +* hyphen (-), file names beginning with: Options. (line 64) * hyphen (-), in bracket expressions: Bracket Expressions. (line 25) * i debugger command (alias for info): Debugger Info. (line 13) * id utility: Id Program. (line 6) @@ -34876,6 +35373,8 @@ Index * implementation issues, gawk, debugging: Compatibility Mode. (line 6) * implementation issues, gawk, limits: Getline Notes. (line 14) * implementation issues, gawk, limits <1>: Redirection. (line 129) +* implicit namespace: Changing The Namespace. + (line 25) * in operator: Comparison Operators. (line 11) * in operator <1>: Precedence. (line 82) @@ -34926,7 +35425,7 @@ Index * installing gawk: Installation. (line 6) * instruction tracing, in debugger: Debugger Info. (line 90) * int: Numeric Functions. (line 24) -* INT signal (MS-Windows): Profiling. (line 212) +* INT signal (MS-Windows): Profiling. (line 214) * integer array indices: Numeric Array Subscripts. (line 31) * integers, arbitrary precision: Arbitrary Precision Integers. @@ -34982,7 +35481,7 @@ Index * Kernighan, Brian <8>: Other Versions. (line 13) * Kernighan, Brian <9>: Basic Data Typing. (line 54) * Kernighan, Brian <10>: Glossary. (line 204) -* kill command, dynamic profiling: Profiling. (line 186) +* kill command, dynamic profiling: Profiling. (line 188) * knights, jedi: Undocumented. (line 6) * Kwok, Conrad: Contributors. (line 35) * l debugger command (alias for list): Miscellaneous Debugger Commands. @@ -35053,9 +35552,9 @@ Index * lint checking, array subscripts: Uninitialized Subscripts. (line 43) * lint checking, empty programs: Command Line. (line 16) -* lint checking, issuing warnings: Options. (line 198) +* lint checking, issuing warnings: Options. (line 210) * lint checking, POSIXLY_CORRECT environment variable: Options. - (line 356) + (line 368) * lint checking, undefined functions: Pass By Value/Reference. (line 85) * LINT variable: User-modified. (line 90) @@ -35068,10 +35567,10 @@ Index * list function definitions, in debugger: Debugger Info. (line 30) * loading extensions, @load directive: Loading Shared Libraries. (line 8) -* loading, extensions: Options. (line 186) +* loading, extensions: Options. (line 198) * local variables, in a function: Variable Scope. (line 6) * locale categories: Explaining gettext. (line 81) -* locale decimal point character: Options. (line 282) +* locale decimal point character: Options. (line 294) * locale, definition of: Locales. (line 6) * localization: I18N and L10N. (line 6) * localization, See internationalization, localization: I18N and L10N. @@ -35119,7 +35618,7 @@ Index * mawk utility <2>: Concatenation. (line 36) * mawk utility <3>: Nextfile Statement. (line 47) * mawk utility <4>: Other Versions. (line 39) -* maximum precision supported by MPFR library: Auto-set. (line 255) +* maximum precision supported by MPFR library: Auto-set. (line 276) * McIlroy, Doug: Glossary. (line 255) * McPhee, Patrick: Contributors. (line 103) * memory, allocating for extensions: Memory Allocation Functions. @@ -35134,9 +35633,10 @@ Index * messages from extensions: Printing Messages. (line 6) * metacharacters in regular expressions: Regexp Operators. (line 6) * metacharacters, escape sequences for: Escape Sequences. (line 140) -* minimum precision required by MPFR library: Auto-set. (line 258) +* minimum precision required by MPFR library: Auto-set. (line 279) * mktime: Time Functions. (line 25) * modifiers, in format specifiers: Format Modifiers. (line 6) +* module, definition of: Global Namespace. (line 18) * monetary information, localization: Explaining gettext. (line 104) * Moore, Duncan: Getline Notes. (line 40) * MPFR, checking availability of: Checking for MPFR. (line 6) @@ -35147,16 +35647,41 @@ Index * multiple-line records: Multiple Line. (line 6) * n debugger command (alias for next): Debugger Execution Control. (line 43) +* name management: Internal Name Management. + (line 6) * names, arrays/variables: Library Names. (line 6) * names, functions: Definition Syntax. (line 24) * names, functions <1>: Library Names. (line 6) * namespace issues: Library Names. (line 6) * namespace issues, functions: Definition Syntax. (line 24) +* namespace names, naming rules: Naming Rules. (line 6) +* namespace, awk: Default Namespace. (line 6) +* namespace, default: Default Namespace. (line 6) +* namespace, definition of: Global Namespace. (line 6) +* namespace, example code: Namespace Example. (line 6) +* namespace, implicit: Changing The Namespace. + (line 25) +* namespace, pushing and popping: Changing The Namespace. + (line 29) +* namespace, standard awk, global: Global Namespace. (line 6) +* namespaces, backwards compatibility: Namespace Summary. (line 28) +* namespaces, changing: Changing The Namespace. + (line 6) +* namespaces, interaction with debugger: Namespace And Features. + (line 17) +* namespaces, interaction with extension API: Namespace And Features. + (line 22) +* namespaces, interaction with pretty printer: Namespace And Features. + (line 9) +* namespaces, interaction with profiler: Namespace And Features. + (line 9) +* namespaces, qualified names: Qualified Names. (line 6) +* naming rules, namespaces and component names: Naming Rules. (line 6) * NetBSD: Glossary. (line 746) * networks, programming: TCP/IP Networking. (line 6) * networks, support for: Special Network. (line 6) * newlines: Statements/Lines. (line 6) -* newlines <1>: Options. (line 276) +* newlines <1>: Options. (line 288) * newlines <2>: Boolean Ops. (line 69) * newlines, as record separators: awk split records. (line 12) * newlines, in dynamic regexps: Computed Regexps. (line 60) @@ -35194,7 +35719,7 @@ Index * not Boolean-logic operator: Boolean Ops. (line 6) * NR variable: Records. (line 6) * NR variable <1>: Auto-set. (line 143) -* NR variable, changing: Auto-set. (line 389) +* NR variable, changing: Auto-set. (line 409) * null strings: awk split records. (line 121) * null strings <1>: Regexp Field Splitting. (line 43) @@ -35231,7 +35756,7 @@ Index * o debugger command (alias for option): Debugger Info. (line 57) * obsolete features: Obsolete. (line 6) * octal numbers: Nondecimal-numbers. (line 6) -* octal values, enabling interpretation of: Options. (line 223) +* octal values, enabling interpretation of: Options. (line 235) * OFMT variable: OFMT. (line 15) * OFMT variable <1>: Strings And Numbers. (line 56) * OFMT variable <2>: User-modified. (line 107) @@ -35279,13 +35804,13 @@ Index (line 66) * option debugger command: Debugger Info. (line 57) * options, command-line: Options. (line 6) -* options, command-line, end of: Options. (line 55) +* options, command-line, end of: Options. (line 59) * options, command-line, invoking awk: Command Line. (line 6) * options, command-line, processing: Getopt Function. (line 6) * options, deprecated: Obsolete. (line 6) * options, long: Command Line. (line 13) * options, long <1>: Options. (line 6) -* options, printing list of: Options. (line 168) +* options, printing list of: Options. (line 176) * or: Bitwise Functions. (line 50) * OR bitwise operation: Bitwise Functions. (line 6) * or Boolean-logic operator: Boolean Ops. (line 6) @@ -35313,8 +35838,9 @@ Index * output, standard: Special FD. (line 6) * p debugger command (alias for print): Viewing And Changing Data. (line 35) +* package, definition of: Global Namespace. (line 18) * Papadopoulos, Panos: Contributors. (line 131) -* parent process ID of gawk process: Auto-set. (line 230) +* parent process ID of gawk process: Auto-set. (line 251) * parentheses (), in a profile: Profiling. (line 146) * parentheses (), regexp operator: Regexp Operators. (line 81) * password file: Passwd Functions. (line 16) @@ -35350,6 +35876,7 @@ Index * pipe, output: Redirection. (line 57) * Pitts, Dave: Acknowledgments. (line 60) * Pitts, Dave <1>: Maintainers. (line 14) +* platform running on, PROCINFO["platform"]: Auto-set. (line 224) * Plauger, P.J.: Library Functions. (line 12) * plug-in: Extension Intro. (line 6) * plus sign (+), + operator: Precedence. (line 51) @@ -35386,13 +35913,13 @@ Index * portability, NF variable, decrementing: Changing Fields. (line 115) * portability, operators: Increment Ops. (line 60) * portability, operators, not in POSIX awk: Precedence. (line 97) -* portability, POSIXLY_CORRECT environment variable: Options. (line 376) +* portability, POSIXLY_CORRECT environment variable: Options. (line 388) * portability, substr() function: String Functions. (line 518) * portable object files: Explaining gettext. (line 37) * portable object files <1>: Translator i18n. (line 6) * portable object files, converting to message object files: I18N Example. (line 80) -* portable object files, generating: Options. (line 161) +* portable object files, generating: Options. (line 169) * portable object template files: Explaining gettext. (line 31) * porting gawk: New Ports. (line 6) * positional specifiers, printf statement: Format Modifiers. (line 13) @@ -35434,23 +35961,25 @@ Index * 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 56) -* POSIX mode: Options. (line 270) -* POSIX mode <1>: Options. (line 356) +* POSIX mode: Options. (line 282) +* POSIX mode <1>: Options. (line 368) * 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 356) +* POSIXLY_CORRECT environment variable: Options. (line 368) * PREC variable: User-modified. (line 127) * precedence: Increment Ops. (line 60) * precedence <1>: Precedence. (line 6) * precedence, regexp operators: Regexp Operators. (line 156) * predefined variables: Built-in Variables. (line 6) -* predefined variables, -v option, setting with: Options. (line 41) +* predefined variables, -v option, setting with: Options. (line 45) * predefined variables, conveying information: Auto-set. (line 6) * predefined variables, user-modifiable: User-modified. (line 6) -* pretty printing: Options. (line 235) -* pretty printing <1>: Profiling. (line 220) -* pretty-printing, profiling, difference with: Profiling. (line 227) +* pretty printer, interaction with namespaces: Namespace And Features. + (line 9) +* pretty printing: Options. (line 247) +* pretty printing <1>: Profiling. (line 222) +* pretty-printing, profiling, difference with: Profiling. (line 229) * print debugger command: Viewing And Changing Data. (line 35) * print statement: Printing. (line 16) @@ -35484,13 +36013,13 @@ Index * printf statement, syntax of: Basic Printf. (line 6) * printing: Printing. (line 6) * printing messages from extensions: Printing Messages. (line 6) -* printing, list of options: Options. (line 168) +* printing, list of options: Options. (line 176) * printing, mailing labels: Labels Program. (line 6) * printing, unduplicated lines of text: Uniq Program. (line 6) * printing, user information: Id Program. (line 6) * private variables: Library Names. (line 11) -* process group ID of gawk process: Auto-set. (line 224) -* process ID of gawk process: Auto-set. (line 227) +* process group ID of gawk process: Auto-set. (line 245) +* process ID of gawk process: Auto-set. (line 248) * processes, two-way communications with: Two-way I/O. (line 6) * processing data: Basic High Level. (line 6) * PROCINFO array: Auto-set. (line 148) @@ -35503,9 +36032,11 @@ Index * PROCINFO array, user and group ID numbers and: Id Program. (line 15) * PROCINFO, values of sorted_in: Controlling Scanning. (line 26) +* profiler, interaction with namespaces: Namespace And Features. + (line 9) * profiling awk programs: Profiling. (line 6) -* profiling awk programs, dynamically: Profiling. (line 177) -* profiling, pretty-printing, difference with: Profiling. (line 227) +* profiling awk programs, dynamically: Profiling. (line 179) +* profiling, pretty-printing, difference with: Profiling. (line 229) * program identifiers: Auto-set. (line 193) * program, definition of: Getting Started. (line 21) * programming conventions, --non-decimal-data option: Nondecimal Data. @@ -35535,6 +36066,8 @@ Index * q debugger command (alias for quit): Miscellaneous Debugger Commands. (line 100) * QSE awk: Other Versions. (line 139) +* qualified name, definition of: Qualified Names. (line 6) +* qualified name, use of: Qualified Names. (line 17) * Quanstrom, Erik: Alarm Program. (line 8) * question mark (?), ?: operator: Precedence. (line 91) * question mark (?), regexp operator: Regexp Operators. (line 111) @@ -35543,7 +36076,7 @@ Index * QuikTrim Awk: Other Versions. (line 143) * quit debugger command: Miscellaneous Debugger Commands. (line 100) -* QUIT signal (MS-Windows): Profiling. (line 212) +* QUIT signal (MS-Windows): Profiling. (line 214) * quoting, for small awk programs: Comments. (line 27) * quoting, in gawk command lines: Long. (line 26) * quoting, in gawk command lines, tricks for: Quoting. (line 91) @@ -35629,7 +36162,7 @@ Index (line 60) * regular expressions, gawk, command-line options: GNU Regexp Operators. (line 73) -* regular expressions, interval expressions and: Options. (line 291) +* regular expressions, interval expressions and: Options. (line 303) * regular expressions, leftmost longest match: Leftmost Longest. (line 6) * regular expressions, operators: Regexp Usage. (line 19) @@ -35670,7 +36203,7 @@ Index * right shift: Bitwise Functions. (line 54) * right shift, bitwise: Bitwise Functions. (line 32) * Ritchie, Dennis: Basic Data Typing. (line 54) -* RLENGTH variable: Auto-set. (line 314) +* RLENGTH variable: Auto-set. (line 335) * RLENGTH variable, match() function and: String Functions. (line 228) * Robbins, Arnold: Command Line Field Separator. (line 71) @@ -35698,12 +36231,12 @@ Index * RS variable <1>: User-modified. (line 136) * RS variable, multiline records and: Multiple Line. (line 17) * rshift: Bitwise Functions. (line 54) -* RSTART variable: Auto-set. (line 320) +* RSTART variable: Auto-set. (line 341) * RSTART variable, match() function and: String Functions. (line 228) * RT variable: awk split records. (line 131) * RT variable <1>: gawk split records. (line 58) * RT variable <2>: Multiple Line. (line 130) -* RT variable <3>: Auto-set. (line 327) +* RT variable <3>: Auto-set. (line 348) * Rubin, Paul: History. (line 30) * Rubin, Paul <1>: Contributors. (line 16) * rule, definition of: Getting Started. (line 21) @@ -35714,14 +36247,14 @@ Index (line 68) * sample debugging session: Sample Debugging Session. (line 6) -* sandbox mode: Options. (line 303) +* sandbox mode: Options. (line 315) * save debugger options: Debugger Info. (line 85) * 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: Acknowledgments. (line 60) -* Schorr, Andrew <1>: Auto-set. (line 359) +* Schorr, Andrew <1>: Auto-set. (line 379) * Schorr, Andrew <2>: Contributors. (line 136) * Schreiber, Bert: Acknowledgments. (line 38) * Schreiber, Rita: Acknowledgments. (line 38) @@ -35808,7 +36341,7 @@ Index * sidebar, Beware The Smoke and Mirrors!: Bitwise Functions. (line 127) * sidebar, Changing FS Does Not Affect the Fields: Full Line Fields. (line 14) -* sidebar, Changing NR and FNR: Auto-set. (line 387) +* sidebar, Changing NR and FNR: Auto-set. (line 407) * sidebar, Controlling Output Buffering with system(): I/O Functions. (line 166) * sidebar, Escape Sequences for Metacharacters: Escape Sequences. @@ -35836,15 +36369,15 @@ Index (line 130) * sidebar, Using \n in Bracket Expressions of Dynamic Regexps: Computed Regexps. (line 58) -* SIGHUP signal, for dynamic profiling: Profiling. (line 209) -* SIGINT signal (MS-Windows): Profiling. (line 212) -* signals, HUP/SIGHUP, for profiling: Profiling. (line 209) -* signals, INT/SIGINT (MS-Windows): Profiling. (line 212) -* signals, QUIT/SIGQUIT (MS-Windows): Profiling. (line 212) -* signals, USR1/SIGUSR1, for profiling: Profiling. (line 186) +* 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) * signature program: Signature Program. (line 6) -* SIGQUIT signal (MS-Windows): Profiling. (line 212) -* SIGUSR1 signal, for dynamic profiling: Profiling. (line 186) +* SIGQUIT signal (MS-Windows): Profiling. (line 214) +* SIGUSR1 signal, for dynamic profiling: Profiling. (line 188) * silent debugger command: Debugger Execution Control. (line 10) * sin: Numeric Functions. (line 75) @@ -35882,7 +36415,7 @@ Index * source code, jawk: Other Versions. (line 121) * source code, libmawk: Other Versions. (line 129) * source code, mawk: Other Versions. (line 39) -* source code, mixing: Options. (line 117) +* source code, mixing: Options. (line 121) * source code, pawk: Other Versions. (line 78) * source code, pawk (Python version): Other Versions. (line 133) * source code, QSE awk: Other Versions. (line 139) @@ -35976,9 +36509,9 @@ Index * substr: String Functions. (line 487) * substring: String Functions. (line 487) * Sumner, Andrew: Other Versions. (line 64) -* supplementary groups of gawk process: Auto-set. (line 271) +* supplementary groups of gawk process: Auto-set. (line 292) * switch statement: Switch Statement. (line 6) -* SYMTAB array: Auto-set. (line 331) +* SYMTAB array: Auto-set. (line 352) * syntactic ambiguity: /= operator vs. /=.../ regexp constant: Assignment Ops. (line 149) * system: I/O Functions. (line 106) @@ -36043,7 +36576,7 @@ Index * translate string: I18N Functions. (line 21) * translate.awk program: Translate Program. (line 55) * treating files, as single records: gawk split records. (line 92) -* troubleshooting, --non-decimal-data option: Options. (line 223) +* troubleshooting, --non-decimal-data option: Options. (line 235) * troubleshooting, == operator: Comparison Operators. (line 37) * troubleshooting, awk uses FS not IFS: Field Separators. (line 29) @@ -36074,7 +36607,7 @@ Index * troubleshooting, substr() function: String Functions. (line 505) * troubleshooting, system() function: I/O Functions. (line 128) * troubleshooting, typographical errors, global variables: Options. - (line 99) + (line 103) * true, logical: Truth Values. (line 6) * Trueman, David: History. (line 30) * Trueman, David <1>: Acknowledgments. (line 47) @@ -36118,6 +36651,7 @@ Index * unwatch debugger command: Viewing And Changing Data. (line 83) * up debugger command: Execution Stack. (line 36) +* uppercase names, namespace for: Default Namespace. (line 10) * user database, reading: Passwd Functions. (line 6) * user-defined functions: User-defined. (line 6) * user-defined, functions, counts, in a profile: Profiling. (line 137) @@ -36125,7 +36659,7 @@ 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 186) +* USR1 signal, for dynamic profiling: Profiling. (line 188) * values, numeric: Basic Data Typing. (line 13) * values, regexp: Strong Regexp Constants. (line 24) @@ -36147,14 +36681,14 @@ Index * variables, getline command into, using <3>: Getline/Variable/Coprocess. (line 6) * variables, global, for library functions: Library Names. (line 11) -* variables, global, printing list of: Options. (line 94) +* variables, global, printing list of: Options. (line 98) * variables, initializing: Using Variables. (line 23) * variables, local to a function: Variable Scope. (line 6) * variables, predefined: Built-in Variables. (line 6) -* variables, predefined, -v option, setting with: Options. (line 41) +* variables, predefined, -v option, setting with: Options. (line 45) * variables, predefined, conveying information: Auto-set. (line 6) * variables, private: Library Names. (line 11) -* variables, setting: Options. (line 32) +* variables, setting: Options. (line 36) * variables, shadowing: Definition Syntax. (line 77) * variables, types of: Assignment Ops. (line 39) * variables, types of, comparison expressions and: Typing and Comparison. @@ -36162,10 +36696,10 @@ Index * variables, uninitialized, as array subscripts: Uninitialized Subscripts. (line 6) * variables, user-defined: Variables. (line 6) -* version of gawk: Auto-set. (line 241) -* version of gawk extension API: Auto-set. (line 266) -* version of GNU MP library: Auto-set. (line 249) -* version of GNU MPFR library: Auto-set. (line 251) +* version of gawk: Auto-set. (line 262) +* version of gawk extension API: Auto-set. (line 287) +* version of GNU MP library: Auto-set. (line 270) +* version of GNU MPFR library: Auto-set. (line 272) * vertical bar (|): Regexp Operators. (line 70) * vertical bar (|), | operator (I/O): Getline/Pipe. (line 10) * vertical bar (|), | operator (I/O) <1>: Precedence. (line 64) @@ -36186,7 +36720,7 @@ Index * Wall, Larry: Array Intro. (line 6) * Wall, Larry <1>: Future Extensions. (line 6) * Wallin, Anders: Contributors. (line 106) -* warnings, issuing: Options. (line 198) +* warnings, issuing: Options. (line 210) * watch debugger command: Viewing And Changing Data. (line 66) * watchpoint (debugger): Debugging Terms. (line 42) @@ -36201,7 +36735,7 @@ Index * whitespace, as field separators: Default Field Splitting. (line 6) * whitespace, functions, calling: Calling Built-in. (line 10) -* whitespace, newlines as: Options. (line 276) +* whitespace, newlines as: Options. (line 288) * Williams, Kent: Contributors. (line 35) * Woehlke, Matthew: Contributors. (line 82) * Woods, John: Contributors. (line 28) @@ -36231,583 +36765,594 @@ Index Tag Table: Node: Top1200 -Node: Foreword343320 -Node: Foreword447762 -Node: Preface49294 -Ref: Preface-Footnote-152153 -Ref: Preface-Footnote-252260 -Ref: Preface-Footnote-352494 -Node: History52636 -Node: Names54988 -Ref: Names-Footnote-156082 -Node: This Manual56229 -Ref: This Manual-Footnote-162714 -Node: Conventions62814 -Node: Manual History65169 -Ref: Manual History-Footnote-168166 -Ref: Manual History-Footnote-268207 -Node: How To Contribute68281 -Node: Acknowledgments69207 -Node: Getting Started74115 -Node: Running gawk76554 -Node: One-shot77744 -Node: Read Terminal79007 -Node: Long81000 -Node: Executable Scripts82513 -Ref: Executable Scripts-Footnote-185308 -Node: Comments85411 -Node: Quoting87895 -Node: DOS Quoting93412 -Node: Sample Data Files95468 -Node: Very Simple98063 -Node: Two Rules102965 -Node: More Complex104850 -Node: Statements/Lines107716 -Ref: Statements/Lines-Footnote-1112175 -Node: Other Features112440 -Node: When113376 -Ref: When-Footnote-1115130 -Node: Intro Summary115195 -Node: Invoking Gawk116079 -Node: Command Line117593 -Node: Options118391 -Ref: Options-Footnote-1134953 -Ref: Options-Footnote-2135184 -Node: Other Arguments135209 -Node: Naming Standard Input138156 -Node: Environment Variables139366 -Node: AWKPATH Variable139924 -Ref: AWKPATH Variable-Footnote-1143336 -Ref: AWKPATH Variable-Footnote-2143370 -Node: AWKLIBPATH Variable143631 -Node: Other Environment Variables145289 -Node: Exit Status149110 -Node: Include Files149787 -Node: Loading Shared Libraries153312 -Node: Obsolete154740 -Node: Undocumented155432 -Node: Invoking Summary155729 -Node: Regexp157389 -Node: Regexp Usage158843 -Node: Escape Sequences160880 -Node: Regexp Operators167112 -Ref: Regexp Operators-Footnote-1174528 -Ref: Regexp Operators-Footnote-2174675 -Node: Bracket Expressions174773 -Ref: table-char-classes177249 -Node: Leftmost Longest180575 -Node: Computed Regexps181878 -Node: GNU Regexp Operators185305 -Node: Case-sensitivity188984 -Ref: Case-sensitivity-Footnote-1191871 -Ref: Case-sensitivity-Footnote-2192106 -Node: Regexp Summary192214 -Node: Reading Files193680 -Node: Records195949 -Node: awk split records197024 -Node: gawk split records202299 -Ref: gawk split records-Footnote-1206885 -Node: Fields206922 -Node: Nonconstant Fields209663 -Ref: Nonconstant Fields-Footnote-1211899 -Node: Changing Fields212103 -Node: Field Separators218134 -Node: Default Field Splitting220832 -Node: Regexp Field Splitting221950 -Node: Single Character Fields225303 -Node: Command Line Field Separator226363 -Node: Full Line Fields229581 -Ref: Full Line Fields-Footnote-1231103 -Ref: Full Line Fields-Footnote-2231149 -Node: Field Splitting Summary231250 -Node: Constant Size233324 -Node: Fixed width data234056 -Node: Skipping intervening237523 -Node: Allowing trailing data238321 -Node: Fields with fixed data239358 -Node: Splitting By Content240876 -Ref: Splitting By Content-Footnote-1244526 -Node: Testing field creation244689 -Node: Multiple Line246314 -Ref: Multiple Line-Footnote-1252198 -Node: Getline252377 -Node: Plain Getline254846 -Node: Getline/Variable257487 -Node: Getline/File258638 -Node: Getline/Variable/File260026 -Ref: Getline/Variable/File-Footnote-1261631 -Node: Getline/Pipe261719 -Node: Getline/Variable/Pipe264426 -Node: Getline/Coprocess265561 -Node: Getline/Variable/Coprocess266828 -Node: Getline Notes267570 -Node: Getline Summary270367 -Ref: table-getline-variants270791 -Node: Read Timeout271539 -Ref: Read Timeout-Footnote-1275445 -Node: Retrying Input275503 -Node: Command-line directories276702 -Node: Input Summary277608 -Node: Input Exercises280780 -Node: Printing281508 -Node: Print283342 -Node: Print Examples284799 -Node: Output Separators287579 -Node: OFMT289596 -Node: Printf290952 -Node: Basic Printf291737 -Node: Control Letters293311 -Node: Format Modifiers298473 -Node: Printf Examples304488 -Node: Redirection306974 -Node: Special FD313815 -Ref: Special FD-Footnote-1316983 -Node: Special Files317057 -Node: Other Inherited Files317674 -Node: Special Network318675 -Node: Special Caveats319535 -Node: Close Files And Pipes320484 -Ref: table-close-pipe-return-values327391 -Ref: Close Files And Pipes-Footnote-1328204 -Ref: Close Files And Pipes-Footnote-2328352 -Node: Nonfatal328504 -Node: Output Summary330842 -Node: Output Exercises332064 -Node: Expressions332743 -Node: Values333931 -Node: Constants334609 -Node: Scalar Constants335300 -Ref: Scalar Constants-Footnote-1337825 -Node: Nondecimal-numbers338075 -Node: Regexp Constants341076 -Node: Using Constant Regexps341602 -Node: Standard Regexp Constants342224 -Node: Strong Regexp Constants345412 -Node: Variables348370 -Node: Using Variables349027 -Node: Assignment Options350937 -Node: Conversion353404 -Node: Strings And Numbers353928 -Ref: Strings And Numbers-Footnote-1356991 -Node: Locale influences conversions357100 -Ref: table-locale-affects359858 -Node: All Operators360476 -Node: Arithmetic Ops361105 -Node: Concatenation363611 -Ref: Concatenation-Footnote-1366458 -Node: Assignment Ops366565 -Ref: table-assign-ops371556 -Node: Increment Ops372869 -Node: Truth Values and Conditions376329 -Node: Truth Values377403 -Node: Typing and Comparison378451 -Node: Variable Typing379271 -Ref: Variable Typing-Footnote-1385734 -Ref: Variable Typing-Footnote-2385806 -Node: Comparison Operators385883 -Ref: table-relational-ops386302 -Node: POSIX String Comparison389797 -Ref: POSIX String Comparison-Footnote-1391492 -Ref: POSIX String Comparison-Footnote-2391631 -Node: Boolean Ops391715 -Ref: Boolean Ops-Footnote-1396197 -Node: Conditional Exp396289 -Node: Function Calls398025 -Node: Precedence401902 -Node: Locales405561 -Node: Expressions Summary407193 -Node: Patterns and Actions409766 -Node: Pattern Overview410886 -Node: Regexp Patterns412563 -Node: Expression Patterns413105 -Node: Ranges416886 -Node: BEGIN/END419994 -Node: Using BEGIN/END420755 -Ref: Using BEGIN/END-Footnote-1423491 -Node: I/O And BEGIN/END423597 -Node: BEGINFILE/ENDFILE425911 -Node: Empty428824 -Node: Using Shell Variables429141 -Node: Action Overview431415 -Node: Statements433740 -Node: If Statement435588 -Node: While Statement437083 -Node: Do Statement439111 -Node: For Statement440259 -Node: Switch Statement443430 -Node: Break Statement445816 -Node: Continue Statement447908 -Node: Next Statement449735 -Node: Nextfile Statement452118 -Node: Exit Statement454770 -Node: Built-in Variables457173 -Node: User-modified458306 -Node: Auto-set466073 -Ref: Auto-set-Footnote-1482375 -Ref: Auto-set-Footnote-2482581 -Node: ARGC and ARGV482637 -Node: Pattern Action Summary486850 -Node: Arrays489280 -Node: Array Basics490609 -Node: Array Intro491453 -Ref: figure-array-elements493428 -Ref: Array Intro-Footnote-1496132 -Node: Reference to Elements496260 -Node: Assigning Elements498724 -Node: Array Example499215 -Node: Scanning an Array500974 -Node: Controlling Scanning503996 -Ref: Controlling Scanning-Footnote-1509395 -Node: Numeric Array Subscripts509711 -Node: Uninitialized Subscripts511895 -Node: Delete513514 -Ref: Delete-Footnote-1516266 -Node: Multidimensional516323 -Node: Multiscanning519418 -Node: Arrays of Arrays521009 -Node: Arrays Summary525777 -Node: Functions527870 -Node: Built-in528908 -Node: Calling Built-in529989 -Node: Numeric Functions531985 -Ref: Numeric Functions-Footnote-1536013 -Ref: Numeric Functions-Footnote-2536370 -Ref: Numeric Functions-Footnote-3536418 -Node: String Functions536690 -Ref: String Functions-Footnote-1560548 -Ref: String Functions-Footnote-2560676 -Ref: String Functions-Footnote-3560924 -Node: Gory Details561011 -Ref: table-sub-escapes562802 -Ref: table-sub-proposed564321 -Ref: table-posix-sub565684 -Ref: table-gensub-escapes567225 -Ref: Gory Details-Footnote-1568048 -Node: I/O Functions568202 -Ref: table-system-return-values574670 -Ref: I/O Functions-Footnote-1576750 -Ref: I/O Functions-Footnote-2576898 -Node: Time Functions577018 -Ref: Time Functions-Footnote-1587689 -Ref: Time Functions-Footnote-2587757 -Ref: Time Functions-Footnote-3587915 -Ref: Time Functions-Footnote-4588026 -Ref: Time Functions-Footnote-5588138 -Ref: Time Functions-Footnote-6588365 -Node: Bitwise Functions588631 -Ref: table-bitwise-ops589225 -Ref: Bitwise Functions-Footnote-1595288 -Ref: Bitwise Functions-Footnote-2595461 -Node: Type Functions595652 -Node: I18N Functions598403 -Node: User-defined600054 -Node: Definition Syntax600859 -Ref: Definition Syntax-Footnote-1606546 -Node: Function Example606617 -Ref: Function Example-Footnote-1609539 -Node: Function Caveats609561 -Node: Calling A Function610079 -Node: Variable Scope611037 -Node: Pass By Value/Reference614031 -Node: Return Statement617530 -Node: Dynamic Typing620509 -Node: Indirect Calls621439 -Ref: Indirect Calls-Footnote-1631691 -Node: Functions Summary631819 -Node: Library Functions634524 -Ref: Library Functions-Footnote-1638131 -Ref: Library Functions-Footnote-2638274 -Node: Library Names638445 -Ref: Library Names-Footnote-1641905 -Ref: Library Names-Footnote-2642128 -Node: General Functions642214 -Node: Strtonum Function643317 -Node: Assert Function646339 -Node: Round Function649665 -Node: Cliff Random Function651205 -Node: Ordinal Functions652221 -Ref: Ordinal Functions-Footnote-1655284 -Ref: Ordinal Functions-Footnote-2655536 -Node: Join Function655746 -Ref: Join Function-Footnote-1657516 -Node: Getlocaltime Function657716 -Node: Readfile Function661458 -Node: Shell Quoting663435 -Node: Data File Management664836 -Node: Filetrans Function665468 -Node: Rewind Function669564 -Node: File Checking671474 -Ref: File Checking-Footnote-1672808 -Node: Empty Files673009 -Node: Ignoring Assigns674988 -Node: Getopt Function676538 -Ref: Getopt Function-Footnote-1688007 -Node: Passwd Functions688207 -Ref: Passwd Functions-Footnote-1697046 -Node: Group Functions697134 -Ref: Group Functions-Footnote-1705032 -Node: Walking Arrays705239 -Node: Library Functions Summary708247 -Node: Library Exercises709653 -Node: Sample Programs710118 -Node: Running Examples710888 -Node: Clones711616 -Node: Cut Program712840 -Node: Egrep Program722769 -Ref: Egrep Program-Footnote-1730281 -Node: Id Program730391 -Node: Split Program734071 -Ref: Split Program-Footnote-1737529 -Node: Tee Program737658 -Node: Uniq Program740448 -Node: Wc Program747874 -Ref: Wc Program-Footnote-1752129 -Node: Miscellaneous Programs752223 -Node: Dupword Program753436 -Node: Alarm Program755466 -Node: Translate Program760321 -Ref: Translate Program-Footnote-1764886 -Node: Labels Program765156 -Ref: Labels Program-Footnote-1768507 -Node: Word Sorting768591 -Node: History Sorting772663 -Node: Extract Program774498 -Node: Simple Sed782552 -Node: Igawk Program785626 -Ref: Igawk Program-Footnote-1799957 -Ref: Igawk Program-Footnote-2800159 -Ref: Igawk Program-Footnote-3800281 -Node: Anagram Program800396 -Node: Signature Program803458 -Node: Programs Summary804705 -Node: Programs Exercises805919 -Ref: Programs Exercises-Footnote-1810048 -Node: Advanced Features810139 -Node: Nondecimal Data812129 -Node: Array Sorting813720 -Node: Controlling Array Traversal814420 -Ref: Controlling Array Traversal-Footnote-1822788 -Node: Array Sorting Functions822906 -Ref: Array Sorting Functions-Footnote-1827997 -Node: Two-way I/O828193 -Ref: Two-way I/O-Footnote-1835914 -Ref: Two-way I/O-Footnote-2836101 -Node: TCP/IP Networking836183 -Node: Profiling839301 -Ref: Profiling-Footnote-1847986 -Node: Advanced Features Summary848309 -Node: Internationalization850153 -Node: I18N and L10N851633 -Node: Explaining gettext852320 -Ref: Explaining gettext-Footnote-1858212 -Ref: Explaining gettext-Footnote-2858397 -Node: Programmer i18n858562 -Ref: Programmer i18n-Footnote-1863511 -Node: Translator i18n863560 -Node: String Extraction864354 -Ref: String Extraction-Footnote-1865486 -Node: Printf Ordering865572 -Ref: Printf Ordering-Footnote-1868358 -Node: I18N Portability868422 -Ref: I18N Portability-Footnote-1870878 -Node: I18N Example870941 -Ref: I18N Example-Footnote-1874216 -Ref: I18N Example-Footnote-2874289 -Node: Gawk I18N874398 -Node: I18N Summary875043 -Node: Debugger876384 -Node: Debugging877404 -Node: Debugging Concepts877845 -Node: Debugging Terms879654 -Node: Awk Debugging882229 -Ref: Awk Debugging-Footnote-1883174 -Node: Sample Debugging Session883306 -Node: Debugger Invocation883840 -Node: Finding The Bug885226 -Node: List of Debugger Commands891700 -Node: Breakpoint Control893033 -Node: Debugger Execution Control896727 -Node: Viewing And Changing Data900089 -Node: Execution Stack903463 -Node: Debugger Info905100 -Node: Miscellaneous Debugger Commands909171 -Node: Readline Support914233 -Node: Limitations915129 -Node: Debugging Summary917238 -Node: Arbitrary Precision Arithmetic918517 -Node: Computer Arithmetic920002 -Ref: table-numeric-ranges923768 -Ref: table-floating-point-ranges924261 -Ref: Computer Arithmetic-Footnote-1924919 -Node: Math Definitions924976 -Ref: table-ieee-formats928292 -Ref: Math Definitions-Footnote-1928895 -Node: MPFR features929000 -Node: FP Math Caution930718 -Ref: FP Math Caution-Footnote-1931790 -Node: Inexactness of computations932159 -Node: Inexact representation933119 -Node: Comparing FP Values934479 -Node: Errors accumulate935720 -Node: Getting Accuracy937153 -Node: Try To Round939863 -Node: Setting precision940762 -Ref: table-predefined-precision-strings941459 -Node: Setting the rounding mode943289 -Ref: table-gawk-rounding-modes943663 -Ref: Setting the rounding mode-Footnote-1947594 -Node: Arbitrary Precision Integers947773 -Ref: Arbitrary Precision Integers-Footnote-1950948 -Node: Checking for MPFR951097 -Node: POSIX Floating Point Problems952571 -Ref: POSIX Floating Point Problems-Footnote-1956856 -Node: Floating point summary956894 -Node: Dynamic Extensions959084 -Node: Extension Intro960637 -Node: Plugin License961903 -Node: Extension Mechanism Outline962700 -Ref: figure-load-extension963139 -Ref: figure-register-new-function964704 -Ref: figure-call-new-function965796 -Node: Extension API Description967858 -Node: Extension API Functions Introduction969500 -Node: General Data Types975040 -Ref: General Data Types-Footnote-1983401 -Node: Memory Allocation Functions983700 -Ref: Memory Allocation Functions-Footnote-1987910 -Node: Constructor Functions988009 -Node: Registration Functions991595 -Node: Extension Functions992280 -Node: Exit Callback Functions997495 -Node: Extension Version String998745 -Node: Input Parsers999408 -Node: Output Wrappers1012129 -Node: Two-way processors1016641 -Node: Printing Messages1018906 -Ref: Printing Messages-Footnote-11020077 -Node: Updating ERRNO1020230 -Node: Requesting Values1020969 -Ref: table-value-types-returned1021706 -Node: Accessing Parameters1022642 -Node: Symbol Table Access1023877 -Node: Symbol table by name1024389 -Node: Symbol table by cookie1026178 -Ref: Symbol table by cookie-Footnote-11030363 -Node: Cached values1030427 -Ref: Cached values-Footnote-11033963 -Node: Array Manipulation1034116 -Ref: Array Manipulation-Footnote-11035207 -Node: Array Data Types1035244 -Ref: Array Data Types-Footnote-11037902 -Node: Array Functions1037994 -Node: Flattening Arrays1042492 -Node: Creating Arrays1049468 -Node: Redirection API1054235 -Node: Extension API Variables1057068 -Node: Extension Versioning1057779 -Ref: gawk-api-version1058208 -Node: Extension GMP/MPFR Versioning1059939 -Node: Extension API Informational Variables1061567 -Node: Extension API Boilerplate1062640 -Node: Changes from API V11066614 -Node: Finding Extensions1068186 -Node: Extension Example1068745 -Node: Internal File Description1069543 -Node: Internal File Ops1073623 -Ref: Internal File Ops-Footnote-11084973 -Node: Using Internal File Ops1085113 -Ref: Using Internal File Ops-Footnote-11087496 -Node: Extension Samples1087770 -Node: Extension Sample File Functions1089299 -Node: Extension Sample Fnmatch1096948 -Node: Extension Sample Fork1098435 -Node: Extension Sample Inplace1099653 -Node: Extension Sample Ord1102870 -Node: Extension Sample Readdir1103706 -Ref: table-readdir-file-types1104595 -Node: Extension Sample Revout1105400 -Node: Extension Sample Rev2way1105989 -Node: Extension Sample Read write array1106729 -Node: Extension Sample Readfile1108671 -Node: Extension Sample Time1109766 -Node: Extension Sample API Tests1111114 -Node: gawkextlib1111606 -Node: Extension summary1114524 -Node: Extension Exercises1118226 -Node: Language History1119724 -Node: V7/SVR3.11121380 -Node: SVR41123532 -Node: POSIX1124966 -Node: BTL1126346 -Node: POSIX/GNU1127075 -Node: Feature History1132853 -Node: Common Extensions1148712 -Node: Ranges and Locales1149995 -Ref: Ranges and Locales-Footnote-11154611 -Ref: Ranges and Locales-Footnote-21154638 -Ref: Ranges and Locales-Footnote-31154873 -Node: Contributors1155094 -Node: History summary1161039 -Node: Installation1162419 -Node: Gawk Distribution1163363 -Node: Getting1163847 -Node: Extracting1164810 -Node: Distribution contents1166448 -Node: Unix Installation1172928 -Node: Quick Installation1173610 -Node: Shell Startup Files1176024 -Node: Additional Configuration Options1177113 -Node: Configuration Philosophy1179406 -Node: Non-Unix Installation1181775 -Node: PC Installation1182235 -Node: PC Binary Installation1183073 -Node: PC Compiling1183508 -Node: PC Using1184625 -Node: Cygwin1187840 -Node: MSYS1188939 -Node: VMS Installation1189440 -Node: VMS Compilation1190231 -Ref: VMS Compilation-Footnote-11191460 -Node: VMS Dynamic Extensions1191518 -Node: VMS Installation Details1193203 -Node: VMS Running1195456 -Node: VMS GNV1199735 -Node: VMS Old Gawk1200470 -Node: Bugs1200941 -Node: Bug address1201604 -Node: Usenet1204586 -Node: Maintainers1205590 -Node: Other Versions1206851 -Node: Installation summary1213765 -Node: Notes1214967 -Node: Compatibility Mode1215761 -Node: Additions1216543 -Node: Accessing The Source1217468 -Node: Adding Code1218905 -Node: New Ports1225124 -Node: Derived Files1229612 -Ref: Derived Files-Footnote-11235258 -Ref: Derived Files-Footnote-21235293 -Ref: Derived Files-Footnote-31235891 -Node: Future Extensions1236005 -Node: Implementation Limitations1236663 -Node: Extension Design1237846 -Node: Old Extension Problems1238990 -Ref: Old Extension Problems-Footnote-11240508 -Node: Extension New Mechanism Goals1240565 -Ref: Extension New Mechanism Goals-Footnote-11243929 -Node: Extension Other Design Decisions1244118 -Node: Extension Future Growth1246231 -Node: Notes summary1247067 -Node: Basic Concepts1248242 -Node: Basic High Level1248923 -Ref: figure-general-flow1249205 -Ref: figure-process-flow1249890 -Ref: Basic High Level-Footnote-11253191 -Node: Basic Data Typing1253376 -Node: Glossary1256704 -Node: Copying1288542 -Node: GNU Free Documentation License1326085 -Node: Index1351205 +Node: Foreword344048 +Node: Foreword448490 +Node: Preface50022 +Ref: Preface-Footnote-152881 +Ref: Preface-Footnote-252988 +Ref: Preface-Footnote-353222 +Node: History53364 +Node: Names55716 +Ref: Names-Footnote-156810 +Node: This Manual56957 +Ref: This Manual-Footnote-163596 +Node: Conventions63696 +Node: Manual History66051 +Ref: Manual History-Footnote-169048 +Ref: Manual History-Footnote-269089 +Node: How To Contribute69163 +Node: Acknowledgments70089 +Node: Getting Started74997 +Node: Running gawk77436 +Node: One-shot78626 +Node: Read Terminal79889 +Node: Long81882 +Node: Executable Scripts83395 +Ref: Executable Scripts-Footnote-186190 +Node: Comments86293 +Node: Quoting88777 +Node: DOS Quoting94294 +Node: Sample Data Files96350 +Node: Very Simple98945 +Node: Two Rules103847 +Node: More Complex105732 +Node: Statements/Lines108598 +Ref: Statements/Lines-Footnote-1113057 +Node: Other Features113322 +Node: When114258 +Ref: When-Footnote-1116012 +Node: Intro Summary116077 +Node: Invoking Gawk116961 +Node: Command Line118475 +Node: Options119273 +Ref: Options-Footnote-1136351 +Ref: Options-Footnote-2136582 +Node: Other Arguments136607 +Node: Naming Standard Input139554 +Node: Environment Variables140764 +Node: AWKPATH Variable141322 +Ref: AWKPATH Variable-Footnote-1144734 +Ref: AWKPATH Variable-Footnote-2144768 +Node: AWKLIBPATH Variable145029 +Node: Other Environment Variables146687 +Node: Exit Status150508 +Node: Include Files151185 +Node: Loading Shared Libraries154875 +Node: Obsolete156303 +Node: Undocumented156995 +Node: Invoking Summary157292 +Node: Regexp158952 +Node: Regexp Usage160406 +Node: Escape Sequences162443 +Node: Regexp Operators168675 +Ref: Regexp Operators-Footnote-1176091 +Ref: Regexp Operators-Footnote-2176238 +Node: Bracket Expressions176336 +Ref: table-char-classes178812 +Node: Leftmost Longest182138 +Node: Computed Regexps183441 +Node: GNU Regexp Operators186868 +Node: Case-sensitivity190547 +Ref: Case-sensitivity-Footnote-1193434 +Ref: Case-sensitivity-Footnote-2193669 +Node: Regexp Summary193777 +Node: Reading Files195243 +Node: Records197512 +Node: awk split records198587 +Node: gawk split records203862 +Ref: gawk split records-Footnote-1208448 +Node: Fields208485 +Node: Nonconstant Fields211226 +Ref: Nonconstant Fields-Footnote-1213462 +Node: Changing Fields213666 +Node: Field Separators219697 +Node: Default Field Splitting222395 +Node: Regexp Field Splitting223513 +Node: Single Character Fields226866 +Node: Command Line Field Separator227926 +Node: Full Line Fields231144 +Ref: Full Line Fields-Footnote-1232666 +Ref: Full Line Fields-Footnote-2232712 +Node: Field Splitting Summary232813 +Node: Constant Size234887 +Node: Fixed width data235619 +Node: Skipping intervening239086 +Node: Allowing trailing data239884 +Node: Fields with fixed data240921 +Node: Splitting By Content242439 +Ref: Splitting By Content-Footnote-1246089 +Node: Testing field creation246252 +Node: Multiple Line247877 +Ref: Multiple Line-Footnote-1253761 +Node: Getline253940 +Node: Plain Getline256409 +Node: Getline/Variable259050 +Node: Getline/File260201 +Node: Getline/Variable/File261589 +Ref: Getline/Variable/File-Footnote-1263194 +Node: Getline/Pipe263282 +Node: Getline/Variable/Pipe265989 +Node: Getline/Coprocess267124 +Node: Getline/Variable/Coprocess268391 +Node: Getline Notes269133 +Node: Getline Summary271930 +Ref: table-getline-variants272354 +Node: Read Timeout273102 +Ref: Read Timeout-Footnote-1277008 +Node: Retrying Input277066 +Node: Command-line directories278265 +Node: Input Summary279171 +Node: Input Exercises282343 +Node: Printing283071 +Node: Print284905 +Node: Print Examples286362 +Node: Output Separators289142 +Node: OFMT291159 +Node: Printf292515 +Node: Basic Printf293300 +Node: Control Letters294874 +Node: Format Modifiers300036 +Node: Printf Examples306051 +Node: Redirection308537 +Node: Special FD315378 +Ref: Special FD-Footnote-1318546 +Node: Special Files318620 +Node: Other Inherited Files319237 +Node: Special Network320238 +Node: Special Caveats321098 +Node: Close Files And Pipes322047 +Ref: table-close-pipe-return-values328954 +Ref: Close Files And Pipes-Footnote-1329767 +Ref: Close Files And Pipes-Footnote-2329915 +Node: Nonfatal330067 +Node: Output Summary332405 +Node: Output Exercises333627 +Node: Expressions334306 +Node: Values335494 +Node: Constants336172 +Node: Scalar Constants336863 +Ref: Scalar Constants-Footnote-1339388 +Node: Nondecimal-numbers339638 +Node: Regexp Constants342639 +Node: Using Constant Regexps343165 +Node: Standard Regexp Constants343787 +Node: Strong Regexp Constants346975 +Node: Variables349933 +Node: Using Variables350590 +Node: Assignment Options352500 +Node: Conversion354967 +Node: Strings And Numbers355491 +Ref: Strings And Numbers-Footnote-1358554 +Node: Locale influences conversions358663 +Ref: table-locale-affects361421 +Node: All Operators362039 +Node: Arithmetic Ops362668 +Node: Concatenation365174 +Ref: Concatenation-Footnote-1368021 +Node: Assignment Ops368128 +Ref: table-assign-ops373119 +Node: Increment Ops374432 +Node: Truth Values and Conditions377892 +Node: Truth Values378966 +Node: Typing and Comparison380014 +Node: Variable Typing380834 +Ref: Variable Typing-Footnote-1387297 +Ref: Variable Typing-Footnote-2387369 +Node: Comparison Operators387446 +Ref: table-relational-ops387865 +Node: POSIX String Comparison391360 +Ref: POSIX String Comparison-Footnote-1393055 +Ref: POSIX String Comparison-Footnote-2393194 +Node: Boolean Ops393278 +Ref: Boolean Ops-Footnote-1397760 +Node: Conditional Exp397852 +Node: Function Calls399588 +Node: Precedence403465 +Node: Locales407124 +Node: Expressions Summary408756 +Node: Patterns and Actions411329 +Node: Pattern Overview412449 +Node: Regexp Patterns414126 +Node: Expression Patterns414668 +Node: Ranges418449 +Node: BEGIN/END421557 +Node: Using BEGIN/END422318 +Ref: Using BEGIN/END-Footnote-1425054 +Node: I/O And BEGIN/END425160 +Node: BEGINFILE/ENDFILE427474 +Node: Empty430387 +Node: Using Shell Variables430704 +Node: Action Overview432978 +Node: Statements435303 +Node: If Statement437151 +Node: While Statement438646 +Node: Do Statement440674 +Node: For Statement441822 +Node: Switch Statement444993 +Node: Break Statement447379 +Node: Continue Statement449471 +Node: Next Statement451298 +Node: Nextfile Statement453681 +Node: Exit Statement456333 +Node: Built-in Variables458736 +Node: User-modified459869 +Node: Auto-set467636 +Ref: Auto-set-Footnote-1484443 +Ref: Auto-set-Footnote-2484649 +Node: ARGC and ARGV484705 +Node: Pattern Action Summary488918 +Node: Arrays491348 +Node: Array Basics492677 +Node: Array Intro493521 +Ref: figure-array-elements495496 +Ref: Array Intro-Footnote-1498200 +Node: Reference to Elements498328 +Node: Assigning Elements500792 +Node: Array Example501283 +Node: Scanning an Array503042 +Node: Controlling Scanning506064 +Ref: Controlling Scanning-Footnote-1511463 +Node: Numeric Array Subscripts511779 +Node: Uninitialized Subscripts513963 +Node: Delete515582 +Ref: Delete-Footnote-1518334 +Node: Multidimensional518391 +Node: Multiscanning521486 +Node: Arrays of Arrays523077 +Node: Arrays Summary527845 +Node: Functions529938 +Node: Built-in530976 +Node: Calling Built-in532057 +Node: Numeric Functions534053 +Ref: Numeric Functions-Footnote-1538081 +Ref: Numeric Functions-Footnote-2538438 +Ref: Numeric Functions-Footnote-3538486 +Node: String Functions538758 +Ref: String Functions-Footnote-1562616 +Ref: String Functions-Footnote-2562744 +Ref: String Functions-Footnote-3562992 +Node: Gory Details563079 +Ref: table-sub-escapes564870 +Ref: table-sub-proposed566389 +Ref: table-posix-sub567752 +Ref: table-gensub-escapes569293 +Ref: Gory Details-Footnote-1570116 +Node: I/O Functions570270 +Ref: table-system-return-values576738 +Ref: I/O Functions-Footnote-1578818 +Ref: I/O Functions-Footnote-2578966 +Node: Time Functions579086 +Ref: Time Functions-Footnote-1589757 +Ref: Time Functions-Footnote-2589825 +Ref: Time Functions-Footnote-3589983 +Ref: Time Functions-Footnote-4590094 +Ref: Time Functions-Footnote-5590206 +Ref: Time Functions-Footnote-6590433 +Node: Bitwise Functions590699 +Ref: table-bitwise-ops591293 +Ref: Bitwise Functions-Footnote-1597356 +Ref: Bitwise Functions-Footnote-2597529 +Node: Type Functions597720 +Node: I18N Functions600471 +Node: User-defined602122 +Node: Definition Syntax602927 +Ref: Definition Syntax-Footnote-1608614 +Node: Function Example608685 +Ref: Function Example-Footnote-1611607 +Node: Function Caveats611629 +Node: Calling A Function612147 +Node: Variable Scope613105 +Node: Pass By Value/Reference616099 +Node: Return Statement619598 +Node: Dynamic Typing622577 +Node: Indirect Calls623507 +Ref: Indirect Calls-Footnote-1633759 +Node: Functions Summary633887 +Node: Library Functions636592 +Ref: Library Functions-Footnote-1640199 +Ref: Library Functions-Footnote-2640342 +Node: Library Names640513 +Ref: Library Names-Footnote-1644180 +Ref: Library Names-Footnote-2644403 +Node: General Functions644489 +Node: Strtonum Function645592 +Node: Assert Function648614 +Node: Round Function651940 +Node: Cliff Random Function653480 +Node: Ordinal Functions654496 +Ref: Ordinal Functions-Footnote-1657559 +Ref: Ordinal Functions-Footnote-2657811 +Node: Join Function658021 +Ref: Join Function-Footnote-1659791 +Node: Getlocaltime Function659991 +Node: Readfile Function663733 +Node: Shell Quoting665710 +Node: Data File Management667111 +Node: Filetrans Function667743 +Node: Rewind Function671839 +Node: File Checking673749 +Ref: File Checking-Footnote-1675083 +Node: Empty Files675284 +Node: Ignoring Assigns677263 +Node: Getopt Function678813 +Ref: Getopt Function-Footnote-1690282 +Node: Passwd Functions690482 +Ref: Passwd Functions-Footnote-1699321 +Node: Group Functions699409 +Ref: Group Functions-Footnote-1707307 +Node: Walking Arrays707514 +Node: Library Functions Summary710522 +Node: Library Exercises711928 +Node: Sample Programs712393 +Node: Running Examples713163 +Node: Clones713891 +Node: Cut Program715115 +Node: Egrep Program725044 +Ref: Egrep Program-Footnote-1732556 +Node: Id Program732666 +Node: Split Program736346 +Ref: Split Program-Footnote-1739804 +Node: Tee Program739933 +Node: Uniq Program742723 +Node: Wc Program750344 +Ref: Wc Program-Footnote-1754599 +Node: Miscellaneous Programs754693 +Node: Dupword Program755906 +Node: Alarm Program757936 +Node: Translate Program762791 +Ref: Translate Program-Footnote-1767356 +Node: Labels Program767626 +Ref: Labels Program-Footnote-1770977 +Node: Word Sorting771061 +Node: History Sorting775133 +Node: Extract Program776968 +Node: Simple Sed785022 +Node: Igawk Program788096 +Ref: Igawk Program-Footnote-1802427 +Ref: Igawk Program-Footnote-2802629 +Ref: Igawk Program-Footnote-3802751 +Node: Anagram Program802866 +Node: Signature Program805928 +Node: Programs Summary807175 +Node: Programs Exercises808389 +Ref: Programs Exercises-Footnote-1812518 +Node: Advanced Features812609 +Node: Nondecimal Data814599 +Node: Array Sorting816190 +Node: Controlling Array Traversal816890 +Ref: Controlling Array Traversal-Footnote-1825258 +Node: Array Sorting Functions825376 +Ref: Array Sorting Functions-Footnote-1830467 +Node: Two-way I/O830663 +Ref: Two-way I/O-Footnote-1838384 +Ref: Two-way I/O-Footnote-2838571 +Node: TCP/IP Networking838653 +Node: Profiling841771 +Node: Advanced Features Summary850789 +Node: Internationalization852633 +Node: I18N and L10N854113 +Node: Explaining gettext854800 +Ref: Explaining gettext-Footnote-1860692 +Ref: Explaining gettext-Footnote-2860877 +Node: Programmer i18n861042 +Ref: Programmer i18n-Footnote-1865991 +Node: Translator i18n866040 +Node: String Extraction866834 +Ref: String Extraction-Footnote-1867966 +Node: Printf Ordering868052 +Ref: Printf Ordering-Footnote-1870838 +Node: I18N Portability870902 +Ref: I18N Portability-Footnote-1873358 +Node: I18N Example873421 +Ref: I18N Example-Footnote-1876696 +Ref: I18N Example-Footnote-2876769 +Node: Gawk I18N876878 +Node: I18N Summary877523 +Node: Debugger878864 +Node: Debugging879864 +Node: Debugging Concepts880305 +Node: Debugging Terms882114 +Node: Awk Debugging884689 +Ref: Awk Debugging-Footnote-1885634 +Node: Sample Debugging Session885766 +Node: Debugger Invocation886300 +Node: Finding The Bug887686 +Node: List of Debugger Commands894160 +Node: Breakpoint Control895493 +Node: Debugger Execution Control899187 +Node: Viewing And Changing Data902549 +Node: Execution Stack905923 +Node: Debugger Info907560 +Node: Miscellaneous Debugger Commands911631 +Node: Readline Support916693 +Node: Limitations917589 +Node: Debugging Summary919698 +Node: Namespaces920977 +Node: Global Namespace921795 +Node: Qualified Names923193 +Node: Default Namespace924192 +Node: Changing The Namespace924933 +Node: Naming Rules926547 +Node: Internal Name Management928395 +Node: Namespace Example929437 +Node: Namespace And Features931999 +Node: Namespace Summary933434 +Node: Arbitrary Precision Arithmetic934911 +Node: Computer Arithmetic936398 +Ref: table-numeric-ranges940164 +Ref: table-floating-point-ranges940657 +Ref: Computer Arithmetic-Footnote-1941315 +Node: Math Definitions941372 +Ref: table-ieee-formats944688 +Ref: Math Definitions-Footnote-1945291 +Node: MPFR features945396 +Node: FP Math Caution947114 +Ref: FP Math Caution-Footnote-1948186 +Node: Inexactness of computations948555 +Node: Inexact representation949515 +Node: Comparing FP Values950875 +Node: Errors accumulate952116 +Node: Getting Accuracy953549 +Node: Try To Round956259 +Node: Setting precision957158 +Ref: table-predefined-precision-strings957855 +Node: Setting the rounding mode959685 +Ref: table-gawk-rounding-modes960059 +Ref: Setting the rounding mode-Footnote-1963990 +Node: Arbitrary Precision Integers964169 +Ref: Arbitrary Precision Integers-Footnote-1967344 +Node: Checking for MPFR967493 +Node: POSIX Floating Point Problems968967 +Ref: POSIX Floating Point Problems-Footnote-1973252 +Node: Floating point summary973290 +Node: Dynamic Extensions975480 +Node: Extension Intro977033 +Node: Plugin License978299 +Node: Extension Mechanism Outline979096 +Ref: figure-load-extension979535 +Ref: figure-register-new-function981100 +Ref: figure-call-new-function982192 +Node: Extension API Description984254 +Node: Extension API Functions Introduction985896 +Ref: table-api-std-headers987732 +Node: General Data Types991597 +Ref: General Data Types-Footnote-1999958 +Node: Memory Allocation Functions1000257 +Ref: Memory Allocation Functions-Footnote-11004467 +Node: Constructor Functions1004566 +Node: Registration Functions1008152 +Node: Extension Functions1008837 +Node: Exit Callback Functions1014159 +Node: Extension Version String1015409 +Node: Input Parsers1016072 +Node: Output Wrappers1028793 +Node: Two-way processors1033305 +Node: Printing Messages1035570 +Ref: Printing Messages-Footnote-11036741 +Node: Updating ERRNO1036894 +Node: Requesting Values1037633 +Ref: table-value-types-returned1038370 +Node: Accessing Parameters1039306 +Node: Symbol Table Access1040541 +Node: Symbol table by name1041053 +Ref: Symbol table by name-Footnote-11044077 +Node: Symbol table by cookie1044205 +Ref: Symbol table by cookie-Footnote-11048390 +Node: Cached values1048454 +Ref: Cached values-Footnote-11051990 +Node: Array Manipulation1052143 +Ref: Array Manipulation-Footnote-11053234 +Node: Array Data Types1053271 +Ref: Array Data Types-Footnote-11055929 +Node: Array Functions1056021 +Node: Flattening Arrays1060519 +Node: Creating Arrays1067495 +Node: Redirection API1072262 +Node: Extension API Variables1075095 +Node: Extension Versioning1075806 +Ref: gawk-api-version1076235 +Node: Extension GMP/MPFR Versioning1077966 +Node: Extension API Informational Variables1079594 +Node: Extension API Boilerplate1080667 +Node: Changes from API V11084641 +Node: Finding Extensions1086213 +Node: Extension Example1086772 +Node: Internal File Description1087570 +Node: Internal File Ops1091650 +Ref: Internal File Ops-Footnote-11103000 +Node: Using Internal File Ops1103140 +Ref: Using Internal File Ops-Footnote-11105523 +Node: Extension Samples1105797 +Node: Extension Sample File Functions1107326 +Node: Extension Sample Fnmatch1114975 +Node: Extension Sample Fork1116462 +Node: Extension Sample Inplace1117680 +Node: Extension Sample Ord1120984 +Node: Extension Sample Readdir1121820 +Ref: table-readdir-file-types1122709 +Node: Extension Sample Revout1123514 +Node: Extension Sample Rev2way1124103 +Node: Extension Sample Read write array1124843 +Node: Extension Sample Readfile1126785 +Node: Extension Sample Time1127880 +Node: Extension Sample API Tests1129228 +Node: gawkextlib1129720 +Node: Extension summary1132638 +Node: Extension Exercises1136340 +Node: Language History1137582 +Node: V7/SVR3.11139238 +Node: SVR41141390 +Node: POSIX1142824 +Node: BTL1144204 +Node: POSIX/GNU1144933 +Node: Feature History1150711 +Node: Common Extensions1166757 +Node: Ranges and Locales1168040 +Ref: Ranges and Locales-Footnote-11172656 +Ref: Ranges and Locales-Footnote-21172683 +Ref: Ranges and Locales-Footnote-31172918 +Node: Contributors1173139 +Node: History summary1179084 +Node: Installation1180464 +Node: Gawk Distribution1181408 +Node: Getting1181892 +Node: Extracting1182855 +Node: Distribution contents1184493 +Node: Unix Installation1190973 +Node: Quick Installation1191655 +Node: Shell Startup Files1194069 +Node: Additional Configuration Options1195158 +Node: Configuration Philosophy1197323 +Node: Non-Unix Installation1199692 +Node: PC Installation1200152 +Node: PC Binary Installation1200990 +Node: PC Compiling1201425 +Node: PC Using1202542 +Node: Cygwin1206095 +Node: MSYS1207194 +Node: VMS Installation1207695 +Node: VMS Compilation1208486 +Ref: VMS Compilation-Footnote-11209715 +Node: VMS Dynamic Extensions1209773 +Node: VMS Installation Details1211458 +Node: VMS Running1213711 +Node: VMS GNV1217990 +Node: VMS Old Gawk1218725 +Node: Bugs1219196 +Node: Bug address1219859 +Node: Usenet1222841 +Node: Maintainers1223845 +Node: Other Versions1225106 +Node: Installation summary1232020 +Node: Notes1233222 +Node: Compatibility Mode1234016 +Node: Additions1234798 +Node: Accessing The Source1235723 +Node: Adding Code1237160 +Node: New Ports1243379 +Node: Derived Files1247867 +Ref: Derived Files-Footnote-11253513 +Ref: Derived Files-Footnote-21253548 +Ref: Derived Files-Footnote-31254146 +Node: Future Extensions1254260 +Node: Implementation Limitations1254918 +Node: Extension Design1256101 +Node: Old Extension Problems1257245 +Ref: Old Extension Problems-Footnote-11258763 +Node: Extension New Mechanism Goals1258820 +Ref: Extension New Mechanism Goals-Footnote-11262184 +Node: Extension Other Design Decisions1262373 +Node: Extension Future Growth1264486 +Node: Notes summary1265322 +Node: Basic Concepts1266497 +Node: Basic High Level1267178 +Ref: figure-general-flow1267460 +Ref: figure-process-flow1268145 +Ref: Basic High Level-Footnote-11271446 +Node: Basic Data Typing1271631 +Node: Glossary1274959 +Node: Copying1306797 +Node: GNU Free Documentation License1344340 +Node: Index1369460 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 102bf23f..58b3ddc7 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -459,6 +459,7 @@ particular records in a file and perform operations upon them. * Internationalization:: Getting @command{gawk} to speak your language. * Debugger:: The @command{gawk} debugger. +* Namespaces:: How namespaces work in @command{gawk}. * Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with @command{gawk}. * Dynamic Extensions:: Adding new built-in functions to @@ -894,6 +895,15 @@ particular records in a file and perform operations upon them. * Readline Support:: Readline support. * Limitations:: Limitations and future plans. * Debugging Summary:: Debugging summary. +* Global Namespace:: The global namespace in standard @command{awk}. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other @command{gawk} features. +* Namespace Summary:: Summarizing namespaces. * Computer Arithmetic:: A quick intro to computer math. * Math Definitions:: Defining terms used. * MPFR features:: The MPFR features in @command{gawk}. @@ -1716,6 +1726,10 @@ messages into different languages at runtime. @ref{Debugger}, describes the @command{gawk} debugger. @item +@ref{Namespaces}, describes how @command{gawk} allows variables and/or +functions of the same name to be in different namespaces. + +@item @ref{Arbitrary Precision Arithmetic}, describes advanced arithmetic facilities. @@ -3826,6 +3840,9 @@ This option may be given multiple times; the @command{awk} program consists of the concatenation of the contents of each specified @var{source-file}. +Files named with @option{-i} are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @item -v @var{var}=@var{val} @itemx --assign @var{var}=@var{val} @cindex @option{-v} option @@ -3971,8 +3988,9 @@ a newline character (even if it doesn't). This makes building the total program easier. @quotation CAUTION -At the moment, there is no requirement that each @var{program-text} -be a full syntactic unit. I.e., the following currently works: +Prior to @value{PVERSION} 5.0, there was +no requirement that each @var{program-text} +be a full syntactic unit. I.e., the following worked: @example $ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'} @@ -3980,8 +3998,12 @@ $ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'} @end example @noindent -However, this could change in the future, so it's not a -good idea to rely upon this feature. +However, this is no longer true. If you have any scripts that +rely upon this feature, you should revise them. + +This is because each @var{program-text} is treated as if it had +@samp{@@namespace "awk"} at its beginning. @xref{Changing The Namespace}, +for more information. @end quotation @item @option{-E} @var{file} @@ -4060,6 +4082,9 @@ input. Thus, after processing an @option{-i} argument, @command{gawk} still expects to find the main source code via the @option{-f} option or on the command line. +Files named with @option{-i} are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @item @option{-l} @var{ext} @itemx @option{--load} @var{ext} @cindex @option{-l} option @@ -4849,6 +4874,10 @@ to be run from web pages. The rules for finding a source file described in @ref{AWKPATH Variable} also apply to files loaded with @code{@@include}. +Finally, files included with @code{@@include} +are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @node Loading Shared Libraries @section Loading Dynamic Extensions into Your Program @@ -4999,6 +5028,15 @@ NaN and Infinity values, instead of the special values @command{gawk} usually produces, as described in @ref{POSIX Floating Point Problems}. This is mainly useful for the included unit tests. +The @code{typeof()} built-in function +(@pxref{Type Functions}) +takes an optional second array argument that, if present, will be cleared +and populated with some information about the internal implementation of +the variable. This can be useful for debugging. At the moment, this +returns a textual version of the flags for scalar variables, and the +array back-end implementation type for arrays. This interface is subject +to change and may not be stable. + @end ignore @node Invoking Summary @@ -15770,6 +15808,30 @@ The values indicate what @command{gawk} knows about the identifiers after it has finished parsing the program; they are @emph{not} updated while the program runs. +@item PROCINFO["platform"] +@cindex platform running on, @code{PROCINFO["platform"]} +This element gives a string indicating the platform for which +@command{gawk} was compiled. The value will be one of the following: + +@c nested table +@table @code +@item "vms" +OpenVMS or Vax/VMS. + +@item "djgpp" +@itemx "mingw" +Microsoft Windows, using either DJGPP or MinGW, respectively. + +@item "os2" +OS/2. + +@item "os390" +OS/390. + +@item "posix" +GNU/Linux, Cygwin, Mac OS X, and legacy Unix systems. +@end table + @item PROCINFO["pgrpid"] @cindex process group ID of @command{gawk} process The process group ID of the current process. @@ -15930,7 +15992,8 @@ if an element in @code{SYMTAB} is an array. Also, you may not use the @code{delete} statement with the @code{SYMTAB} array. -You may use an index for @code{SYMTAB} that is not a predefined identifier: +Prior to @value{PVERSION} 5.0 of @command{gawk}, you could +use an index for @code{SYMTAB} that was not a predefined identifier: @example SYMTAB["xxx"] = 5 @@ -15938,9 +16001,8 @@ print SYMTAB["xxx"] @end example @noindent -This works as expected: in this case @code{SYMTAB} acts just like -a regular array. The only difference is that you can't then delete -@code{SYMTAB["xxx"]}. +This no longer works, instead producing a fatal error, as it led +to rampant confusion. @cindex Schorr, Andrew The @code{SYMTAB} array is more interesting than it looks. Andrew Schorr @@ -21806,6 +21868,11 @@ The conventions presented in this @value{SECTION} are exactly that: conventions. You are not required to write your programs this way---we merely recommend that you do so. +Beginning with @value{PVERSION} 5.0, @command{gawk} provides +a powerful mechanism for solving the problems described in this +section: @dfn{namespaces}. Namespaces and their use are described +in detail in @ref{Namespaces}. + @node General Functions @section General Programming @@ -25704,12 +25771,9 @@ END @{ @c endfile @end example -@c FIXME: Include this? -@ignore -This program does not follow our recommended convention of naming +As a side note, 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 @@ -27935,6 +27999,9 @@ It contains the following chapters: @itemize @value{BULLET} @item +@ref{Namespaces} + +@item @ref{Advanced Features} @item @@ -29119,6 +29186,7 @@ of the program and the precedence rules. For example, @samp{(3 + 5) * 4} means add three and five, then multiply the total by four. However, @samp{3 + 5 * 4} has no parentheses, and means @samp{3 + (5 * 4)}. +However, explicit parentheses in the source program are retained. @ignore @item @@ -29157,12 +29225,14 @@ come out as: @example /foo/ @{ - print $0 + print @} @end example @noindent which is correct, but possibly unexpected. +(If a program uses both @samp{print $0} and plain +@samp{print}, that distinction is retained.) @cindex profiling @command{awk} programs, dynamically @cindex @command{gawk} program, dynamic profiling @@ -29250,12 +29320,10 @@ 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.@footnote{@command{gawk} does the best it can to preserve +source code. However, no comments should be lost. +Also, @command{gawk} does the best it can to preserve the distinction between comments at the end of a statement and comments -on lines by themselves. Due to implementation constraints, it does not -always do so correctly, particularly for @code{switch} statements. The -@command{gawk} maintainers hope to improve this in a subsequent -release.} +on lines by themselves. This isn't always perfect, though. However, as a deliberate design decision, profiling output @emph{omits} the original program's comments. This allows you to focus on the @@ -31663,6 +31731,447 @@ program being debugged, but occasionally it can. @end itemize +@hyphenation{name-space name-spaces Name-space Name-spaces} +@node Namespaces +@chapter Namespaces in @command{gawk} + +This @value{CHAPTER} describes a feature that is specific to @command{gawk}. + +@menu +* Global Namespace:: The global namespace in standard @command{awk}. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other @command{gawk} features. +* Namespace Summary:: Summarizing namespaces. +@end menu + +@node Global Namespace +@section Standard @command{awk}'s Single Namespace + +@cindex namespace, definition of +@cindex namespace, standard @command{awk}, global +In standard @command{awk}, there is a single, global, @dfn{namespace}. +This means that @emph{all} function names and global variable names must +be unique. For example, two different @command{awk} source files cannot +both define a function named @code{min()}, or define the same identifier, +used as a scalar in one and as an array in the other. + +This situation is okay when programs are small, say a few hundred +lines, or even a few thousand, but it prevents the development of +reusable libraries of @command{awk} functions, and can inadvertently +cause independently-developed library files to accidentally step on each +other's ``private'' global variables +(@pxref{Library Names}). + +@cindex package, definition of +@cindex module, definition of +Most other programming languages solve this issue by providing some kind +of namespace control: a way to say ``this function is in namespace @var{xxx}, +and that function is in namespace @var{yyy}.'' (Of course, there is then +still a single namespace for the namespaces, but the hope is that there +are much fewer namespaces in use by any given program, and thus much +less chance for collisions.) These facilities are sometimes referred +to as @dfn{packages} or @dfn{modules}. + +Starting with @value{PVERSION} 5.0, @command{gawk} provides a +simple mechanism to put functions and global variables into separate namespaces. + +@node Qualified Names +@section Qualified Names + +@cindex qualified name, definition of +@cindex namespaces, qualified names +@cindex @code{::}, namespace separator +@cindex component name +A @dfn{qualified name} is an identifier that includes a namespace name, +the namespace separator @code{::}, and a @dfn{component} name. For example, one +might have a function named @code{posix::getpid()}. Here, the namespace +is @code{posix} and the function name within the namespace (the component) +is @code{getpid()}. The namespace and component names are separated by +a double-colon. Only one such separator is allowed in a qualified name. + +@quotation NOTE +Unlike C++, the @code{::} is @emph{not} an operator. No spaces are +allowed between the namespace name, the @code{::}, and the component name. +@end quotation + +@cindex qualified name, use of +You must use qualified names from one namespace to access variables +and functions in another. This is especially important when using +variable names to index the special @code{SYMTAB} array (@pxref{Auto-set}), +and when making indirect function calls (@pxref{Indirect Calls}). + +@node Default Namespace +@section The Default Namespace + +@cindex namespace, default +@cindex namespace, @code{awk} +@cindex @code{awk} namespace +The default namespace, not surprisingly, is @code{awk}. +All of the predefined @command{awk} and @command{gawk} variables +are in this namespace, and thus have qualified names like +@code{awk::ARGC}, @code{awk::NF}, and so on. + +@cindex uppercase names, namespace for +Furthermore, even when you have changed the namespace for your +current source file (@pxref{Changing The Namespace}), @command{gawk} +forces unqualified identifiers whose names are all uppercase letters +to be in the @code{awk} namespace. This makes it possible for you to easily +reference @command{gawk}'s global variables from different namespaces. +It also keeps your code looking natural. + +@node Changing The Namespace +@section Changing The Namespace + +@cindex namespaces, changing +@cindex @code{@@namespace} directive +In order to set the current namespace, use an @code{@@namespace} directive +at the top level of your program: + +@example +@@namespace "passwd" + +BEGIN @{ @dots{} @} +@dots{} +@end example + +After this directive, all simple non-completely-uppercase identifiers are +placed into the @code{passwd} namespace. + +You can change the namespace multiple times within a single +source file, although this is likely to become confusing if you +do it too much. + +@quotation NOTE +Association of unqualified identifiers to a namespace is handled while +@command{gawk} parses your program, @emph{before} it starts to run. There is +no concept of a ``current'' namespace once your program starts executing. +Be sure you understand this. +@end quotation + +@cindex namespace, implicit +@cindex implicit namespace +Each source file for @option{-i} and @option{-f} starts out with +an implicit @samp{@@namespace "awk"}. Similarly, each chunk of +command-line code supplied with @option{-e} has such an implicit +initial statement (@pxref{Options}). + +@cindex current namespace, pushing and popping +@cindex namespace, pushing and popping +Files included with @code{@@include} (@pxref{Include Files}) ``push'' +and ``pop'' the current namespace. That is, each @code{@@include} saves +the current namespace and starts over with an implicit @samp{@@namespace +"awk"} which remains in effect until an explicit @code{@@namespace} +directive is seen. When @command{gawk} finishes processing the included +file, the saved namespace is restored and processing continues where it +left off in the original file. + +@cindex @code{@@namespace}, no effect on @code{BEGIN} @code{BEGINFILE}, @code{END}, and @code{ENDFILE} +@cindex @code{BEGIN}, execution order not affected by @code{@@namespace} +@cindex @code{BEGINFILE}, execution order not affected by @code{@@namespace} +@cindex @code{END}, execution order not affected by @code{@@namespace} +@cindex @code{ENDFILE}, execution order not affected by @code{@@namespace} +The use of @code{@@namespace} has no influence upon the order of execution +of @code{BEGIN}, @code{BEGINFILE}, @code{END}, and @code{ENDFILE} rules. + +@node Naming Rules +@section Namespace and Component Naming Rules + +@cindex naming rules, namespaces and component names +@cindex namespace names, naming rules +@cindex component names, naming rules +A number of rules apply to the namespace and component names, as follows. + +@itemize @bullet +@item +It is a syntax error to use qualified names for function parameter names. + +@item +It is a syntax error to use any standard @command{awk} reserved word (such +as @code{if} or @code{for}), or the name of any standard built-in function +(such as @code{sin()} or @code{gsub()}) as either part of a qualified name. +Thus, the following produces a syntax error: + +@example +@@namespace "example" + +function gsub(str, pat, result) @{ @dots{} @} +@end example + +@item +Outside the @code{awk} namespace, the names of the additional @command{gawk} +built-in functions (such as @code{gensub()} or @code{strftime()}) @emph{may} +be used as component names. The same set of names may be used as namespace +names, although this has the potential to be confusing. + +@item +The additional @command{gawk} built-in functions may still be called +from outside the @code{awk} namespace by qualifying them. For example, +@code{awk::systime()}. Here is a somewhat silly example demonstrating +this rule and the previous one: + +@example +BEGIN @{ + print "in awk namespace, systime() =", systime() +@} + +@@namespace "testing" + +function systime() +@{ + print "in testing namespace, systime() =", awk::systime() +@} + +BEGIN @{ + systime() +@} +@end example + +@noindent + +When run, it produces output like this: + +@example +$ @kbd{gawk -f systime.awk} +@print{} in awk namespace, systime() = 1500488503 +@print{} in testing namespace, systime() = 1500488503 +@end example + +@item +@command{gawk} pre-defined variable names may be used: +@code{NF::NR} is valid, if possibly not all that useful. +@end itemize + +@node Internal Name Management +@section Internal Name Management + +@cindex name management +@cindex @code{awk} namespace, identifier name storage +@cindex @code{awk} namespace, use for indirect function calls +For backwards compatibility, all identifiers in the @code{awk} namespace +are stored internally as unadorned identifiers (that is, without a +leading @samp{awk::}). This is mainly relevant +when using such identifiers as indices for @code{SYMTAB}, @code{FUNCTAB}, +and @code{PROCINFO["identifiers"]} (@pxref{Auto-set}), and for use in +indirect function calls (@pxref{Indirect Calls}). + +In program code, to refer to variables and functions in the @code{awk} +namespace from another namespace, you must still use the @samp{awk::} +prefix. For example: + +@example +@@namespace "awk" @ii{This is the default namespace} + +BEGIN @{ + Title = "My Report" @ii{Qualified name is} awk::Title +@} + +@@namespace "report" @ii{Now in} report @ii{namespace} + +function compute() @ii{This is really} report::compute() +@{ + print awk::Title @ii{But would be} SYMTAB["Title"] + @dots{} +@} +@end example + +@node Namespace Example +@section Namespace Example + +@cindex namespace, example code +The following example is a revised version of the suite of routines +developed in @ref{Passwd Functions}. See there for an explanation +of how the code works. + +The formulation here, due mainly to Andrew Schorr, is rather elegant. +All of the implementation functions and variables are in the +@code{passwd} namespace, whereas the main interface functions are +defined in the @code{awk} namespace. + +@example +@c file eg/lib/ns_passwd.awk +# ns_passwd.awk --- access password file information +@c endfile +@ignore +@c file eg/lib/ns_passwd.awk +# +# Arnold Robbins, arnold@@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 +# +# Reworked for namespaces June 2017, with help from +# Andrew J.@: Schorr, aschorr@@telemetry-investments.com +@c endfile +@end ignore +@c file eg/lib/ns_passwd.awk + +@@namespace "passwd" + +BEGIN @{ + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" +@} + +function Init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +@{ + if (Inited) + return + + oldfs = FS + oldrs = RS + olddol0 = $0 + using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (PROCINFO["FS"] == "FPAT") + FS = ":" + RS = "\n" + + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) @{ + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + @} + close(pwcat) + Count = 0 + Inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +@} + +function awk::getpwnam(name) +@{ + Init() + return Byname[name] +@} + +function awk::getpwuid(uid) +@{ + Init() + return Byuid[uid] +@} + +function awk::getpwent() +@{ + Init() + if (Count < Total) + return Bycount[++Count] + return "" +@} + +function awk::endpwent() +@{ + Count = 0 +@} +@c endfile +@end example + +As you can see, this version also follows the convention mentioned in +@ref{Library Names}, whereby global variable and function names +start with a capital letter. + +Here is a simple test program. Since it's in a separate file, unadorned +identifiers are sought for in the @code{awk} namespace: + +@example +BEGIN @{ + while ((p = getpwent()) != "") + print p +@} +@end example + +@noindent + +Here's what happens when it's run: + +@example +$ @kbd{gawk -f ns_passwd.awk -f testpasswd.awk} +@print{} root:x:0:0:root:/root:/bin/bash +@print{} daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +@print{} bin:x:2:2:bin:/bin:/usr/sbin/nologin +@print{} sys:x:3:3:sys:/dev:/usr/sbin/nologin +@dots{} +@end example + +@node Namespace And Features +@section Namespaces and Other @command{gawk} Features + +This @value{SECTION} looks briefly at how the namespace facility interacts +with other important @command{gawk} features. + +@cindex namespaces, interaction with profiler +@cindex namespaces, interaction with pretty printer +@cindex profiler, interaction with namespaces +@cindex pretty printer, interaction with namespaces +The profiler and pretty-printer (@pxref{Profiling}) have been enhanced +to understand namespaces and the namespace naming rules presented in +@ref{Naming Rules}. In particular, the output groups functions in the same +namespace together, and has @code{@@namespace} directives in front +of rules as necessary. This allows component names to be +simple identifiers, instead of using qualified identifiers everywhere. + +@cindex namespaces, interaction with debugger +@cindex debugger, interaction with namespaces +Interaction with the debugger (@pxref{Debugging}) has not had to change +(at least as of this writing). Some of the internal byte codes changed +in order to accommodate namespaces, and the debugger's @code{dump} command +was adjusted to match. + +@cindex namespaces, interaction with extension API +@cindex extension API, interaction with namespaces +The extension API (@pxref{Dynamic Extensions}) has always allowed for +placing functions into a different namespace, although this was not +previously implemented. However, the symbol lookup and symbol update +routines did not have provision for including a namespace. That has now +been corrected (@pxref{Symbol table by name}). +@xref{Extension Sample Inplace}, for a nice example of an extension that +leverages a namespace shared by cooperating @command{awk} and C code. + +@node Namespace Summary +@section Summary + +@itemize @value{BULLET} +@item +Standard @command{awk} provides a single namespace for all global +identifiers (scalars, arrays, and functions). This is limiting when +one wants to develop libraries of reusable functions or function suites. + +@item +@command{gawk} provides multiple namespaces by using qualified names: +names consisting of a namespace name, a double colon, @code{::}, and a +component name. Namespace names might still possibly conflict, but this +is true of any language providing namespaces, modules, or packages. + +@item +The default namespace is @command{awk}. The rules for namespace and +component names are provided in @ref{Naming Rules}. The rules are +designed in such a way as to make namespace-aware code continue to +look and work naturally while still providing the necessary power and +flexibility. + +@item +Other parts of @command{gawk} have been extended as necessary to integrate +namespaces smoothly with their operation. This applies most notably to +the profiler / pretty-printer (@pxref{Profiling}) and to the extension +facility (@pxref{Dynamic Extensions}). + +@cindex namespaces, backwards compatibility +@item +Overall, the namespace facility was designed and implemented such that +backwards compatibility is paramount. Programs that don't use namespaces +should see absolutely no difference in behavior when run by a namespace-capable +version of @command{gawk}. +@end itemize + @node Arbitrary Precision Arithmetic @chapter Arithmetic and Arbitrary-Precision Arithmetic with @command{gawk} @cindex arbitrary precision @@ -33253,9 +33762,11 @@ Some points about using the API: @item The following types, macros, and/or functions are referenced in @file{gawkapi.h}. For correct use, you must therefore include the -corresponding standard header file @emph{before} including @file{gawkapi.h}: +corresponding standard header file @emph{before} including @file{gawkapi.h}. +The list of macros and related header files is shown in @ref{table-api-std-headers}. -@c FIXME: Make this is a float at some point. +@float Table,table-api-std-headers +@caption{Standard header files needed by API} @multitable {@code{memset()}, @code{memcpy()}} {@code{<sys/types.h>}} @headitem C entity @tab Header file @item @code{EOF} @tab @code{<stdio.h>} @@ -33267,6 +33778,7 @@ corresponding standard header file @emph{before} including @file{gawkapi.h}: @item @code{size_t} @tab @code{<sys/types.h>} @item @code{struct stat} @tab @code{<sys/stat.h>} @end multitable +@end float Due to portability concerns, especially to systems that are not fully standards-compliant, it is your responsibility @@ -33855,8 +34367,11 @@ it with @command{gawk} using this API function: @table @code @item awk_bool_t add_ext_func(const char *name_space, awk_ext_func_t *func); This function returns true upon success, false otherwise. -The @code{name_space} parameter is currently not used; you should pass in an -empty string (@code{""}). The @code{func} pointer is the address of a +The @code{name_space} parameter is the namespace in which to place +the function (@pxref{Namespaces}). +Use an empty string (@code{""}) or @code{"awk"} to place +the function in the default @code{awk} namespace. +The @code{func} pointer is the address of a @code{struct} representing your function, as just described. @command{gawk} does not modify what @code{func} points to, but the @@ -34717,6 +35232,18 @@ Return true if the actual type matches @code{wanted}, and false otherwise. In the latter case, @code{result->val_type} indicates the actual type (@pxref{table-value-types-returned}). +@item awk_bool_t sym_lookup_ns(const char *name, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *name_space, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result); +This is like @code{sym_lookup()}, but the @code{name_space} parameter allows you +to specify which namespace @code{name} is part of. @code{name_space} cannot be +@code{NULL}. If it is @code{""} or @code{"awk"}, then @code{name} is searched +for in the default @code{awk} namespace. + +Note that @code{namespace} is a C++ keyword. For interoperability with C++, +you should avoid using that identifier in C code. + @item awk_bool_t sym_update(const char *name, awk_value_t *value); Update the variable named by the string @code{name}, which is a regular C string. The variable is added to @command{gawk}'s symbol table @@ -34726,12 +35253,25 @@ Changing types (scalar to array or vice versa) of an existing variable is @emph{not} allowed, nor may this routine be used to update an array. This routine cannot be used to update any of the predefined variables (such as @code{ARGC} or @code{NF}). + +@item awk_bool_t sym_update_ns(const char *name_space, const char *name, awk_value_t *value); +This is like @code{sym_update()}, but the @code{name_space} parameter allows you +to specify which namespace @code{name} is part of. @code{name_space} cannot be +@code{NULL}. If it is @code{""} or @code{"awk}, then @code{name} is searched +for in the default @code{awk} namespace. @end table 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. +When searching for or updating variables outside the @code{awk} namespace +(@pxref{Namespaces}), function and variable names must be simple +identifiers.@footnote{Allowing both namespace plus identifier and +@code{foo::bar} would have been too confusing to document, and to code +and test.} In addition, namespace names and variable and function names +must follow the rules given in @ref{Naming Rules}. + @node Symbol table by cookie @subsubsection Variable Access and Update by Cookie @@ -36911,7 +37451,9 @@ else The @code{inplace} extension emulates GNU @command{sed}'s @option{-i} option, which performs ``in-place'' editing of each input file. It uses the bundled @file{inplace.awk} include file to invoke the extension -properly: +properly. This extension makes use of the namespace facility to place +all the variables and functions in the @code{inplace} namespace +(@pxref{Namespaces}): @example @c file eg/lib/inplace.awk @@ -36942,14 +37484,18 @@ properly: # # Andrew J. Schorr, aschorr@@telemetry-investments.com # January 2013 +# +# Revised for namespaces +# Arnold Robbins, arnold@@skeeve.com +# July 2017 @c endfile @end ignore @c file eg/lib/inplace.awk @@load "inplace" -# Please set INPLACE_SUFFIX to make a backup copy. For example, you may -# want to set INPLACE_SUFFIX to .bak on the command line or in a BEGIN rule. +# Please set inplace::suffix to make a backup copy. For example, you may +# want to set inplace::suffix to .bak on the command line or in a BEGIN rule. # By default, each filename on the command line will be edited inplace. # But you can selectively disable this by adding an inplace=0 argument @@ -36957,31 +37503,33 @@ properly: # reenable it later on the commandline by putting inplace=1 before files # that you wish to be subject to inplace editing. -# N.B. We call inplace_end() in the BEGINFILE and END rules so that any +# N.B. We call inplace::end() in the BEGINFILE and END rules so that any # actions in an ENDFILE rule will be redirected as expected. + +@@namespace "inplace" @end group @group BEGIN @{ - inplace = 1 # enabled by default + enable = 1 # enabled by default @} @end group @group BEGINFILE @{ - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) - if (inplace) - inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) + if (enable) + begin(filename = FILENAME, suffix) else - _inplace_filename = "" + filename = "" @} @end group @group END @{ - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) @} @end group @c endfile @@ -36991,17 +37539,18 @@ For each regular file that is processed, the extension redirects standard output to a temporary file configured to have the same owner and permissions as the original. After the file has been processed, the extension restores standard output to its original destination. -If @code{INPLACE_SUFFIX} is not an empty string, the original file is +If @code{inplace::suffix} is not an empty string, the original file is linked to a backup @value{FN} created by appending that suffix. Finally, the temporary file is renamed to the original @value{FN}. -Note that the use of this feature can be controlled by placing @samp{inplace=0} -on the command-line prior to listing files that should not be processed this -way. You can reenable inplace editing by adding an @samp{inplace=1} argument -prior to files that should be subject to inplace editing. +Note that the use of this feature can be controlled by placing +@samp{inplace::enable=0} on the command-line prior to listing files that +should not be processed this way. You can reenable inplace editing by adding +an @samp{inplace::enable=1} argument prior to files that should be subject +to inplace editing. -The @code{_inplace_filename} variable serves to keep track of the -current filename so as to not invoke @code{inplace_end()} before +The @code{inplace::filename} variable serves to keep track of the +current filename so as to not invoke @code{inplace::end()} before processing the first file. If any error occurs, the extension issues a fatal error to terminate @@ -37016,7 +37565,7 @@ $ @kbd{gawk -i inplace '@{ gsub(/foo/, "bar") @}; @{ print @}' file1 file2 file3 To keep a backup copy of the original files, try this: @example -$ @kbd{gawk -i inplace -v INPLACE_SUFFIX=.bak '@{ gsub(/foo/, "bar") @}} +$ @kbd{gawk -i inplace -v inplace::suffix=.bak '@{ gsub(/foo/, "bar") @}} > @kbd{@{ print @}' file1 file2 file3} @end example @@ -37516,13 +38065,6 @@ Which reading mechanism should you replace, the one to get a record, or the one to read raw bytes? @item -(Hard.) -How would you provide namespaces in @command{gawk}, so that the -names of functions in different extensions don't conflict with each other? -If you come up with a really good scheme, contact the @command{gawk} -maintainer to tell him about it. - -@item Write a wrapper script that provides an interface similar to @samp{sed -i} for the ``inplace'' extension presented in @ref{Extension Sample Inplace}. @@ -38942,6 +39484,14 @@ Support for GNU/Linux on Alpha was removed. @end itemize +Version 5.0 added the following features: + +@itemize +@item +The @code{PROCINFO["platform"]} array element, which allows you +to write code that takes the operating system / platform into account. +@end itemize + @c XXX ADD MORE STUFF HERE @end ifclear @@ -39904,11 +40454,6 @@ include the major and minor API versions in it. This makes it possible to keep extensions for different API versions on the same system without their conflicting with one another. -@cindex @option{--with-whiny-user-strftime} configuration option -@cindex configuration option, @code{--with-whiny-user-strftime} -@item --with-whiny-user-strftime -Force use of the included version of the C @code{strftime()} -function for deficient systems. @end table Use the command @samp{./configure --help} to see the full list of @@ -40094,6 +40639,12 @@ appropriate @samp{-v BINMODE=@var{N}} option on the command line. @code{BINMODE} is set at the time a file or pipe is opened and cannot be changed midstream. +On POSIX-compatible systems, this variable's value has no effect. +Thus, if you think your program will run on multiple different systems +and that you may need to use @code{BINMODE}, you should simply set it +(in the program or on the command line) unconditionally, and not worry +about the operating system on which your program is running. + The name @code{BINMODE} was chosen to match @command{mawk} (@pxref{Other Versions}). @command{mawk} and @command{gawk} handle @code{BINMODE} similarly; however, diff --git a/doc/gawktexi.in b/doc/gawktexi.in index ec09b79f..de713811 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -454,6 +454,7 @@ particular records in a file and perform operations upon them. * Internationalization:: Getting @command{gawk} to speak your language. * Debugger:: The @command{gawk} debugger. +* Namespaces:: How namespaces work in @command{gawk}. * Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with @command{gawk}. * Dynamic Extensions:: Adding new built-in functions to @@ -889,6 +890,15 @@ particular records in a file and perform operations upon them. * Readline Support:: Readline support. * Limitations:: Limitations and future plans. * Debugging Summary:: Debugging summary. +* Global Namespace:: The global namespace in standard @command{awk}. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other @command{gawk} features. +* Namespace Summary:: Summarizing namespaces. * Computer Arithmetic:: A quick intro to computer math. * Math Definitions:: Defining terms used. * MPFR features:: The MPFR features in @command{gawk}. @@ -1683,6 +1693,10 @@ messages into different languages at runtime. @ref{Debugger}, describes the @command{gawk} debugger. @item +@ref{Namespaces}, describes how @command{gawk} allows variables and/or +functions of the same name to be in different namespaces. + +@item @ref{Arbitrary Precision Arithmetic}, describes advanced arithmetic facilities. @@ -3736,6 +3750,9 @@ This option may be given multiple times; the @command{awk} program consists of the concatenation of the contents of each specified @var{source-file}. +Files named with @option{-i} are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @item -v @var{var}=@var{val} @itemx --assign @var{var}=@var{val} @cindex @option{-v} option @@ -3881,8 +3898,9 @@ a newline character (even if it doesn't). This makes building the total program easier. @quotation CAUTION -At the moment, there is no requirement that each @var{program-text} -be a full syntactic unit. I.e., the following currently works: +Prior to @value{PVERSION} 5.0, there was +no requirement that each @var{program-text} +be a full syntactic unit. I.e., the following worked: @example $ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'} @@ -3890,8 +3908,12 @@ $ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'} @end example @noindent -However, this could change in the future, so it's not a -good idea to rely upon this feature. +However, this is no longer true. If you have any scripts that +rely upon this feature, you should revise them. + +This is because each @var{program-text} is treated as if it had +@samp{@@namespace "awk"} at its beginning. @xref{Changing The Namespace}, +for more information. @end quotation @item @option{-E} @var{file} @@ -3970,6 +3992,9 @@ input. Thus, after processing an @option{-i} argument, @command{gawk} still expects to find the main source code via the @option{-f} option or on the command line. +Files named with @option{-i} are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @item @option{-l} @var{ext} @itemx @option{--load} @var{ext} @cindex @option{-l} option @@ -4759,6 +4784,10 @@ to be run from web pages. The rules for finding a source file described in @ref{AWKPATH Variable} also apply to files loaded with @code{@@include}. +Finally, files included with @code{@@include} +are treated as if they had @samp{@@namespace "awk"} +at their beginning. @xref{Changing The Namespace}, for more information. + @node Loading Shared Libraries @section Loading Dynamic Extensions into Your Program @@ -4909,6 +4938,15 @@ NaN and Infinity values, instead of the special values @command{gawk} usually produces, as described in @ref{POSIX Floating Point Problems}. This is mainly useful for the included unit tests. +The @code{typeof()} built-in function +(@pxref{Type Functions}) +takes an optional second array argument that, if present, will be cleared +and populated with some information about the internal implementation of +the variable. This can be useful for debugging. At the moment, this +returns a textual version of the flags for scalar variables, and the +array back-end implementation type for arrays. This interface is subject +to change and may not be stable. + @end ignore @node Invoking Summary @@ -15087,6 +15125,30 @@ The values indicate what @command{gawk} knows about the identifiers after it has finished parsing the program; they are @emph{not} updated while the program runs. +@item PROCINFO["platform"] +@cindex platform running on, @code{PROCINFO["platform"]} +This element gives a string indicating the platform for which +@command{gawk} was compiled. The value will be one of the following: + +@c nested table +@table @code +@item "vms" +OpenVMS or Vax/VMS. + +@item "djgpp" +@itemx "mingw" +Microsoft Windows, using either DJGPP or MinGW, respectively. + +@item "os2" +OS/2. + +@item "os390" +OS/390. + +@item "posix" +GNU/Linux, Cygwin, Mac OS X, and legacy Unix systems. +@end table + @item PROCINFO["pgrpid"] @cindex process group ID of @command{gawk} process The process group ID of the current process. @@ -15247,7 +15309,8 @@ if an element in @code{SYMTAB} is an array. Also, you may not use the @code{delete} statement with the @code{SYMTAB} array. -You may use an index for @code{SYMTAB} that is not a predefined identifier: +Prior to @value{PVERSION} 5.0 of @command{gawk}, you could +use an index for @code{SYMTAB} that was not a predefined identifier: @example SYMTAB["xxx"] = 5 @@ -15255,9 +15318,8 @@ print SYMTAB["xxx"] @end example @noindent -This works as expected: in this case @code{SYMTAB} acts just like -a regular array. The only difference is that you can't then delete -@code{SYMTAB["xxx"]}. +This no longer works, instead producing a fatal error, as it led +to rampant confusion. @cindex Schorr, Andrew The @code{SYMTAB} array is more interesting than it looks. Andrew Schorr @@ -20848,6 +20910,11 @@ The conventions presented in this @value{SECTION} are exactly that: conventions. You are not required to write your programs this way---we merely recommend that you do so. +Beginning with @value{PVERSION} 5.0, @command{gawk} provides +a powerful mechanism for solving the problems described in this +section: @dfn{namespaces}. Namespaces and their use are described +in detail in @ref{Namespaces}. + @node General Functions @section General Programming @@ -24716,12 +24783,9 @@ END @{ @c endfile @end example -@c FIXME: Include this? -@ignore -This program does not follow our recommended convention of naming +As a side note, 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 @@ -26947,6 +27011,9 @@ It contains the following chapters: @itemize @value{BULLET} @item +@ref{Namespaces} + +@item @ref{Advanced Features} @item @@ -28131,6 +28198,7 @@ of the program and the precedence rules. For example, @samp{(3 + 5) * 4} means add three and five, then multiply the total by four. However, @samp{3 + 5 * 4} has no parentheses, and means @samp{3 + (5 * 4)}. +However, explicit parentheses in the source program are retained. @ignore @item @@ -28169,12 +28237,14 @@ come out as: @example /foo/ @{ - print $0 + print @} @end example @noindent which is correct, but possibly unexpected. +(If a program uses both @samp{print $0} and plain +@samp{print}, that distinction is retained.) @cindex profiling @command{awk} programs, dynamically @cindex @command{gawk} program, dynamic profiling @@ -28262,12 +28332,10 @@ 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.@footnote{@command{gawk} does the best it can to preserve +source code. However, no comments should be lost. +Also, @command{gawk} does the best it can to preserve the distinction between comments at the end of a statement and comments -on lines by themselves. Due to implementation constraints, it does not -always do so correctly, particularly for @code{switch} statements. The -@command{gawk} maintainers hope to improve this in a subsequent -release.} +on lines by themselves. This isn't always perfect, though. However, as a deliberate design decision, profiling output @emph{omits} the original program's comments. This allows you to focus on the @@ -30675,6 +30743,447 @@ program being debugged, but occasionally it can. @end itemize +@hyphenation{name-space name-spaces Name-space Name-spaces} +@node Namespaces +@chapter Namespaces in @command{gawk} + +This @value{CHAPTER} describes a feature that is specific to @command{gawk}. + +@menu +* Global Namespace:: The global namespace in standard @command{awk}. +* Qualified Names:: How to qualify names with a namespace. +* Default Namespace:: The default namespace. +* Changing The Namespace:: How to change the namespace. +* Naming Rules:: Namespace and Component Naming Rules. +* Internal Name Management:: How names are stored internally. +* Namespace Example:: An example of code using a namespace. +* Namespace And Features:: Namespaces and other @command{gawk} features. +* Namespace Summary:: Summarizing namespaces. +@end menu + +@node Global Namespace +@section Standard @command{awk}'s Single Namespace + +@cindex namespace, definition of +@cindex namespace, standard @command{awk}, global +In standard @command{awk}, there is a single, global, @dfn{namespace}. +This means that @emph{all} function names and global variable names must +be unique. For example, two different @command{awk} source files cannot +both define a function named @code{min()}, or define the same identifier, +used as a scalar in one and as an array in the other. + +This situation is okay when programs are small, say a few hundred +lines, or even a few thousand, but it prevents the development of +reusable libraries of @command{awk} functions, and can inadvertently +cause independently-developed library files to accidentally step on each +other's ``private'' global variables +(@pxref{Library Names}). + +@cindex package, definition of +@cindex module, definition of +Most other programming languages solve this issue by providing some kind +of namespace control: a way to say ``this function is in namespace @var{xxx}, +and that function is in namespace @var{yyy}.'' (Of course, there is then +still a single namespace for the namespaces, but the hope is that there +are much fewer namespaces in use by any given program, and thus much +less chance for collisions.) These facilities are sometimes referred +to as @dfn{packages} or @dfn{modules}. + +Starting with @value{PVERSION} 5.0, @command{gawk} provides a +simple mechanism to put functions and global variables into separate namespaces. + +@node Qualified Names +@section Qualified Names + +@cindex qualified name, definition of +@cindex namespaces, qualified names +@cindex @code{::}, namespace separator +@cindex component name +A @dfn{qualified name} is an identifier that includes a namespace name, +the namespace separator @code{::}, and a @dfn{component} name. For example, one +might have a function named @code{posix::getpid()}. Here, the namespace +is @code{posix} and the function name within the namespace (the component) +is @code{getpid()}. The namespace and component names are separated by +a double-colon. Only one such separator is allowed in a qualified name. + +@quotation NOTE +Unlike C++, the @code{::} is @emph{not} an operator. No spaces are +allowed between the namespace name, the @code{::}, and the component name. +@end quotation + +@cindex qualified name, use of +You must use qualified names from one namespace to access variables +and functions in another. This is especially important when using +variable names to index the special @code{SYMTAB} array (@pxref{Auto-set}), +and when making indirect function calls (@pxref{Indirect Calls}). + +@node Default Namespace +@section The Default Namespace + +@cindex namespace, default +@cindex namespace, @code{awk} +@cindex @code{awk} namespace +The default namespace, not surprisingly, is @code{awk}. +All of the predefined @command{awk} and @command{gawk} variables +are in this namespace, and thus have qualified names like +@code{awk::ARGC}, @code{awk::NF}, and so on. + +@cindex uppercase names, namespace for +Furthermore, even when you have changed the namespace for your +current source file (@pxref{Changing The Namespace}), @command{gawk} +forces unqualified identifiers whose names are all uppercase letters +to be in the @code{awk} namespace. This makes it possible for you to easily +reference @command{gawk}'s global variables from different namespaces. +It also keeps your code looking natural. + +@node Changing The Namespace +@section Changing The Namespace + +@cindex namespaces, changing +@cindex @code{@@namespace} directive +In order to set the current namespace, use an @code{@@namespace} directive +at the top level of your program: + +@example +@@namespace "passwd" + +BEGIN @{ @dots{} @} +@dots{} +@end example + +After this directive, all simple non-completely-uppercase identifiers are +placed into the @code{passwd} namespace. + +You can change the namespace multiple times within a single +source file, although this is likely to become confusing if you +do it too much. + +@quotation NOTE +Association of unqualified identifiers to a namespace is handled while +@command{gawk} parses your program, @emph{before} it starts to run. There is +no concept of a ``current'' namespace once your program starts executing. +Be sure you understand this. +@end quotation + +@cindex namespace, implicit +@cindex implicit namespace +Each source file for @option{-i} and @option{-f} starts out with +an implicit @samp{@@namespace "awk"}. Similarly, each chunk of +command-line code supplied with @option{-e} has such an implicit +initial statement (@pxref{Options}). + +@cindex current namespace, pushing and popping +@cindex namespace, pushing and popping +Files included with @code{@@include} (@pxref{Include Files}) ``push'' +and ``pop'' the current namespace. That is, each @code{@@include} saves +the current namespace and starts over with an implicit @samp{@@namespace +"awk"} which remains in effect until an explicit @code{@@namespace} +directive is seen. When @command{gawk} finishes processing the included +file, the saved namespace is restored and processing continues where it +left off in the original file. + +@cindex @code{@@namespace}, no effect on @code{BEGIN} @code{BEGINFILE}, @code{END}, and @code{ENDFILE} +@cindex @code{BEGIN}, execution order not affected by @code{@@namespace} +@cindex @code{BEGINFILE}, execution order not affected by @code{@@namespace} +@cindex @code{END}, execution order not affected by @code{@@namespace} +@cindex @code{ENDFILE}, execution order not affected by @code{@@namespace} +The use of @code{@@namespace} has no influence upon the order of execution +of @code{BEGIN}, @code{BEGINFILE}, @code{END}, and @code{ENDFILE} rules. + +@node Naming Rules +@section Namespace and Component Naming Rules + +@cindex naming rules, namespaces and component names +@cindex namespace names, naming rules +@cindex component names, naming rules +A number of rules apply to the namespace and component names, as follows. + +@itemize @bullet +@item +It is a syntax error to use qualified names for function parameter names. + +@item +It is a syntax error to use any standard @command{awk} reserved word (such +as @code{if} or @code{for}), or the name of any standard built-in function +(such as @code{sin()} or @code{gsub()}) as either part of a qualified name. +Thus, the following produces a syntax error: + +@example +@@namespace "example" + +function gsub(str, pat, result) @{ @dots{} @} +@end example + +@item +Outside the @code{awk} namespace, the names of the additional @command{gawk} +built-in functions (such as @code{gensub()} or @code{strftime()}) @emph{may} +be used as component names. The same set of names may be used as namespace +names, although this has the potential to be confusing. + +@item +The additional @command{gawk} built-in functions may still be called +from outside the @code{awk} namespace by qualifying them. For example, +@code{awk::systime()}. Here is a somewhat silly example demonstrating +this rule and the previous one: + +@example +BEGIN @{ + print "in awk namespace, systime() =", systime() +@} + +@@namespace "testing" + +function systime() +@{ + print "in testing namespace, systime() =", awk::systime() +@} + +BEGIN @{ + systime() +@} +@end example + +@noindent + +When run, it produces output like this: + +@example +$ @kbd{gawk -f systime.awk} +@print{} in awk namespace, systime() = 1500488503 +@print{} in testing namespace, systime() = 1500488503 +@end example + +@item +@command{gawk} pre-defined variable names may be used: +@code{NF::NR} is valid, if possibly not all that useful. +@end itemize + +@node Internal Name Management +@section Internal Name Management + +@cindex name management +@cindex @code{awk} namespace, identifier name storage +@cindex @code{awk} namespace, use for indirect function calls +For backwards compatibility, all identifiers in the @code{awk} namespace +are stored internally as unadorned identifiers (that is, without a +leading @samp{awk::}). This is mainly relevant +when using such identifiers as indices for @code{SYMTAB}, @code{FUNCTAB}, +and @code{PROCINFO["identifiers"]} (@pxref{Auto-set}), and for use in +indirect function calls (@pxref{Indirect Calls}). + +In program code, to refer to variables and functions in the @code{awk} +namespace from another namespace, you must still use the @samp{awk::} +prefix. For example: + +@example +@@namespace "awk" @ii{This is the default namespace} + +BEGIN @{ + Title = "My Report" @ii{Qualified name is} awk::Title +@} + +@@namespace "report" @ii{Now in} report @ii{namespace} + +function compute() @ii{This is really} report::compute() +@{ + print awk::Title @ii{But would be} SYMTAB["Title"] + @dots{} +@} +@end example + +@node Namespace Example +@section Namespace Example + +@cindex namespace, example code +The following example is a revised version of the suite of routines +developed in @ref{Passwd Functions}. See there for an explanation +of how the code works. + +The formulation here, due mainly to Andrew Schorr, is rather elegant. +All of the implementation functions and variables are in the +@code{passwd} namespace, whereas the main interface functions are +defined in the @code{awk} namespace. + +@example +@c file eg/lib/ns_passwd.awk +# ns_passwd.awk --- access password file information +@c endfile +@ignore +@c file eg/lib/ns_passwd.awk +# +# Arnold Robbins, arnold@@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 +# +# Reworked for namespaces June 2017, with help from +# Andrew J.@: Schorr, aschorr@@telemetry-investments.com +@c endfile +@end ignore +@c file eg/lib/ns_passwd.awk + +@@namespace "passwd" + +BEGIN @{ + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" +@} + +function Init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +@{ + if (Inited) + return + + oldfs = FS + oldrs = RS + olddol0 = $0 + using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (PROCINFO["FS"] == "FPAT") + FS = ":" + RS = "\n" + + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) @{ + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + @} + close(pwcat) + Count = 0 + Inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +@} + +function awk::getpwnam(name) +@{ + Init() + return Byname[name] +@} + +function awk::getpwuid(uid) +@{ + Init() + return Byuid[uid] +@} + +function awk::getpwent() +@{ + Init() + if (Count < Total) + return Bycount[++Count] + return "" +@} + +function awk::endpwent() +@{ + Count = 0 +@} +@c endfile +@end example + +As you can see, this version also follows the convention mentioned in +@ref{Library Names}, whereby global variable and function names +start with a capital letter. + +Here is a simple test program. Since it's in a separate file, unadorned +identifiers are sought for in the @code{awk} namespace: + +@example +BEGIN @{ + while ((p = getpwent()) != "") + print p +@} +@end example + +@noindent + +Here's what happens when it's run: + +@example +$ @kbd{gawk -f ns_passwd.awk -f testpasswd.awk} +@print{} root:x:0:0:root:/root:/bin/bash +@print{} daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +@print{} bin:x:2:2:bin:/bin:/usr/sbin/nologin +@print{} sys:x:3:3:sys:/dev:/usr/sbin/nologin +@dots{} +@end example + +@node Namespace And Features +@section Namespaces and Other @command{gawk} Features + +This @value{SECTION} looks briefly at how the namespace facility interacts +with other important @command{gawk} features. + +@cindex namespaces, interaction with profiler +@cindex namespaces, interaction with pretty printer +@cindex profiler, interaction with namespaces +@cindex pretty printer, interaction with namespaces +The profiler and pretty-printer (@pxref{Profiling}) have been enhanced +to understand namespaces and the namespace naming rules presented in +@ref{Naming Rules}. In particular, the output groups functions in the same +namespace together, and has @code{@@namespace} directives in front +of rules as necessary. This allows component names to be +simple identifiers, instead of using qualified identifiers everywhere. + +@cindex namespaces, interaction with debugger +@cindex debugger, interaction with namespaces +Interaction with the debugger (@pxref{Debugging}) has not had to change +(at least as of this writing). Some of the internal byte codes changed +in order to accommodate namespaces, and the debugger's @code{dump} command +was adjusted to match. + +@cindex namespaces, interaction with extension API +@cindex extension API, interaction with namespaces +The extension API (@pxref{Dynamic Extensions}) has always allowed for +placing functions into a different namespace, although this was not +previously implemented. However, the symbol lookup and symbol update +routines did not have provision for including a namespace. That has now +been corrected (@pxref{Symbol table by name}). +@xref{Extension Sample Inplace}, for a nice example of an extension that +leverages a namespace shared by cooperating @command{awk} and C code. + +@node Namespace Summary +@section Summary + +@itemize @value{BULLET} +@item +Standard @command{awk} provides a single namespace for all global +identifiers (scalars, arrays, and functions). This is limiting when +one wants to develop libraries of reusable functions or function suites. + +@item +@command{gawk} provides multiple namespaces by using qualified names: +names consisting of a namespace name, a double colon, @code{::}, and a +component name. Namespace names might still possibly conflict, but this +is true of any language providing namespaces, modules, or packages. + +@item +The default namespace is @command{awk}. The rules for namespace and +component names are provided in @ref{Naming Rules}. The rules are +designed in such a way as to make namespace-aware code continue to +look and work naturally while still providing the necessary power and +flexibility. + +@item +Other parts of @command{gawk} have been extended as necessary to integrate +namespaces smoothly with their operation. This applies most notably to +the profiler / pretty-printer (@pxref{Profiling}) and to the extension +facility (@pxref{Dynamic Extensions}). + +@cindex namespaces, backwards compatibility +@item +Overall, the namespace facility was designed and implemented such that +backwards compatibility is paramount. Programs that don't use namespaces +should see absolutely no difference in behavior when run by a namespace-capable +version of @command{gawk}. +@end itemize + @node Arbitrary Precision Arithmetic @chapter Arithmetic and Arbitrary-Precision Arithmetic with @command{gawk} @cindex arbitrary precision @@ -32226,9 +32735,11 @@ Some points about using the API: @item The following types, macros, and/or functions are referenced in @file{gawkapi.h}. For correct use, you must therefore include the -corresponding standard header file @emph{before} including @file{gawkapi.h}: +corresponding standard header file @emph{before} including @file{gawkapi.h}. +The list of macros and related header files is shown in @ref{table-api-std-headers}. -@c FIXME: Make this is a float at some point. +@float Table,table-api-std-headers +@caption{Standard header files needed by API} @multitable {@code{memset()}, @code{memcpy()}} {@code{<sys/types.h>}} @headitem C entity @tab Header file @item @code{EOF} @tab @code{<stdio.h>} @@ -32240,6 +32751,7 @@ corresponding standard header file @emph{before} including @file{gawkapi.h}: @item @code{size_t} @tab @code{<sys/types.h>} @item @code{struct stat} @tab @code{<sys/stat.h>} @end multitable +@end float Due to portability concerns, especially to systems that are not fully standards-compliant, it is your responsibility @@ -32828,8 +33340,11 @@ it with @command{gawk} using this API function: @table @code @item awk_bool_t add_ext_func(const char *name_space, awk_ext_func_t *func); This function returns true upon success, false otherwise. -The @code{name_space} parameter is currently not used; you should pass in an -empty string (@code{""}). The @code{func} pointer is the address of a +The @code{name_space} parameter is the namespace in which to place +the function (@pxref{Namespaces}). +Use an empty string (@code{""}) or @code{"awk"} to place +the function in the default @code{awk} namespace. +The @code{func} pointer is the address of a @code{struct} representing your function, as just described. @command{gawk} does not modify what @code{func} points to, but the @@ -33690,6 +34205,18 @@ Return true if the actual type matches @code{wanted}, and false otherwise. In the latter case, @code{result->val_type} indicates the actual type (@pxref{table-value-types-returned}). +@item awk_bool_t sym_lookup_ns(const char *name, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *name_space, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted, +@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result); +This is like @code{sym_lookup()}, but the @code{name_space} parameter allows you +to specify which namespace @code{name} is part of. @code{name_space} cannot be +@code{NULL}. If it is @code{""} or @code{"awk"}, then @code{name} is searched +for in the default @code{awk} namespace. + +Note that @code{namespace} is a C++ keyword. For interoperability with C++, +you should avoid using that identifier in C code. + @item awk_bool_t sym_update(const char *name, awk_value_t *value); Update the variable named by the string @code{name}, which is a regular C string. The variable is added to @command{gawk}'s symbol table @@ -33699,12 +34226,25 @@ Changing types (scalar to array or vice versa) of an existing variable is @emph{not} allowed, nor may this routine be used to update an array. This routine cannot be used to update any of the predefined variables (such as @code{ARGC} or @code{NF}). + +@item awk_bool_t sym_update_ns(const char *name_space, const char *name, awk_value_t *value); +This is like @code{sym_update()}, but the @code{name_space} parameter allows you +to specify which namespace @code{name} is part of. @code{name_space} cannot be +@code{NULL}. If it is @code{""} or @code{"awk}, then @code{name} is searched +for in the default @code{awk} namespace. @end table 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. +When searching for or updating variables outside the @code{awk} namespace +(@pxref{Namespaces}), function and variable names must be simple +identifiers.@footnote{Allowing both namespace plus identifier and +@code{foo::bar} would have been too confusing to document, and to code +and test.} In addition, namespace names and variable and function names +must follow the rules given in @ref{Naming Rules}. + @node Symbol table by cookie @subsubsection Variable Access and Update by Cookie @@ -35884,7 +36424,9 @@ else The @code{inplace} extension emulates GNU @command{sed}'s @option{-i} option, which performs ``in-place'' editing of each input file. It uses the bundled @file{inplace.awk} include file to invoke the extension -properly: +properly. This extension makes use of the namespace facility to place +all the variables and functions in the @code{inplace} namespace +(@pxref{Namespaces}): @example @c file eg/lib/inplace.awk @@ -35915,14 +36457,18 @@ properly: # # Andrew J. Schorr, aschorr@@telemetry-investments.com # January 2013 +# +# Revised for namespaces +# Arnold Robbins, arnold@@skeeve.com +# July 2017 @c endfile @end ignore @c file eg/lib/inplace.awk @@load "inplace" -# Please set INPLACE_SUFFIX to make a backup copy. For example, you may -# want to set INPLACE_SUFFIX to .bak on the command line or in a BEGIN rule. +# Please set inplace::suffix to make a backup copy. For example, you may +# want to set inplace::suffix to .bak on the command line or in a BEGIN rule. # By default, each filename on the command line will be edited inplace. # But you can selectively disable this by adding an inplace=0 argument @@ -35930,31 +36476,33 @@ properly: # reenable it later on the commandline by putting inplace=1 before files # that you wish to be subject to inplace editing. -# N.B. We call inplace_end() in the BEGINFILE and END rules so that any +# N.B. We call inplace::end() in the BEGINFILE and END rules so that any # actions in an ENDFILE rule will be redirected as expected. + +@@namespace "inplace" @end group @group BEGIN @{ - inplace = 1 # enabled by default + enable = 1 # enabled by default @} @end group @group BEGINFILE @{ - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) - if (inplace) - inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) + if (enable) + begin(filename = FILENAME, suffix) else - _inplace_filename = "" + filename = "" @} @end group @group END @{ - if (_inplace_filename != "") - inplace_end(_inplace_filename, INPLACE_SUFFIX) + if (filename != "") + end(filename, suffix) @} @end group @c endfile @@ -35964,17 +36512,18 @@ For each regular file that is processed, the extension redirects standard output to a temporary file configured to have the same owner and permissions as the original. After the file has been processed, the extension restores standard output to its original destination. -If @code{INPLACE_SUFFIX} is not an empty string, the original file is +If @code{inplace::suffix} is not an empty string, the original file is linked to a backup @value{FN} created by appending that suffix. Finally, the temporary file is renamed to the original @value{FN}. -Note that the use of this feature can be controlled by placing @samp{inplace=0} -on the command-line prior to listing files that should not be processed this -way. You can reenable inplace editing by adding an @samp{inplace=1} argument -prior to files that should be subject to inplace editing. +Note that the use of this feature can be controlled by placing +@samp{inplace::enable=0} on the command-line prior to listing files that +should not be processed this way. You can reenable inplace editing by adding +an @samp{inplace::enable=1} argument prior to files that should be subject +to inplace editing. -The @code{_inplace_filename} variable serves to keep track of the -current filename so as to not invoke @code{inplace_end()} before +The @code{inplace::filename} variable serves to keep track of the +current filename so as to not invoke @code{inplace::end()} before processing the first file. If any error occurs, the extension issues a fatal error to terminate @@ -35989,7 +36538,7 @@ $ @kbd{gawk -i inplace '@{ gsub(/foo/, "bar") @}; @{ print @}' file1 file2 file3 To keep a backup copy of the original files, try this: @example -$ @kbd{gawk -i inplace -v INPLACE_SUFFIX=.bak '@{ gsub(/foo/, "bar") @}} +$ @kbd{gawk -i inplace -v inplace::suffix=.bak '@{ gsub(/foo/, "bar") @}} > @kbd{@{ print @}' file1 file2 file3} @end example @@ -36489,13 +37038,6 @@ Which reading mechanism should you replace, the one to get a record, or the one to read raw bytes? @item -(Hard.) -How would you provide namespaces in @command{gawk}, so that the -names of functions in different extensions don't conflict with each other? -If you come up with a really good scheme, contact the @command{gawk} -maintainer to tell him about it. - -@item Write a wrapper script that provides an interface similar to @samp{sed -i} for the ``inplace'' extension presented in @ref{Extension Sample Inplace}. @@ -37915,6 +38457,14 @@ Support for GNU/Linux on Alpha was removed. @end itemize +Version 5.0 added the following features: + +@itemize +@item +The @code{PROCINFO["platform"]} array element, which allows you +to write code that takes the operating system / platform into account. +@end itemize + @c XXX ADD MORE STUFF HERE @end ifclear @@ -38877,11 +39427,6 @@ include the major and minor API versions in it. This makes it possible to keep extensions for different API versions on the same system without their conflicting with one another. -@cindex @option{--with-whiny-user-strftime} configuration option -@cindex configuration option, @code{--with-whiny-user-strftime} -@item --with-whiny-user-strftime -Force use of the included version of the C @code{strftime()} -function for deficient systems. @end table Use the command @samp{./configure --help} to see the full list of @@ -39067,6 +39612,12 @@ appropriate @samp{-v BINMODE=@var{N}} option on the command line. @code{BINMODE} is set at the time a file or pipe is opened and cannot be changed midstream. +On POSIX-compatible systems, this variable's value has no effect. +Thus, if you think your program will run on multiple different systems +and that you may need to use @code{BINMODE}, you should simply set it +(in the program or on the command line) unconditionally, and not worry +about the operating system on which your program is running. + The name @code{BINMODE} was chosen to match @command{mawk} (@pxref{Other Versions}). @command{mawk} and @command{gawk} handle @code{BINMODE} similarly; however, diff --git a/doc/it/ChangeLog b/doc/it/ChangeLog index 662f285c..3e010bb6 100644 --- a/doc/it/ChangeLog +++ b/doc/it/ChangeLog @@ -1,15 +1,73 @@ 2018-12-18 Antonio Giovanni Colombo <azc100@gmail.com> * gawk.1: Updated. + * gawktexi.in: Updated. + +2018-09-07 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in, gawk.1, texinfo.tex: Remove execute permission. + +2018-07-29 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates for NaN/Infinity and pty example + +2018-06-15 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + +2018-06-06 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + +2018-05-25 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + +2018-05-14 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + * texinfo.tex: Updated to current version. + +2018-05-12 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + +2018-03-30 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates. + +2018-03-11 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Updates modified month. 2018-02-25 Arnold D. Robbins <arnold@skeeve.com> * 4.2.1: Release tar ball made. +2018-02-17 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: More updates. + 2017-02-17 Antonio Giovanni Colombo <azc100@gmail.com> * gawk.1: Synchronized with English version. +2018-02-10 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: More updates. + +2018-01-26 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: More updates. + +2018-01-18 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: More updates. + +2017-12-07 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Synchronize with English original. + 2018-01-12 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Remove incorrect '*' on some declarations of @@ -21,6 +79,10 @@ * gawk.1: New file. (Italian translation of the man page.) +2017-12-05 Antonio Giovanni Colombo <azc100@gmail.com> + + * gawktexi.in: Italian translation updated. + 2017-10-19 Arnold D. Robbins <arnold@skeeve.com> * 4.2.0: Release tar ball made. diff --git a/doc/it/gawk.1 b/doc/it/gawk.1 index bcc0c596..bcc0c596 100755..100644 --- a/doc/it/gawk.1 +++ b/doc/it/gawk.1 diff --git a/doc/it/gawktexi.in b/doc/it/gawktexi.in index d29cdf03..5a56e8fc 100644 --- a/doc/it/gawktexi.in +++ b/doc/it/gawktexi.in @@ -61,9 +61,9 @@ @c applies to and all the info about who's publishing this edition @c These apply across the board. -@set UPDATE-MONTH Ottobre 2017 +@set UPDATE-MONTH Settembre 2018 @set VERSION 4.2 -@set PATCHLEVEL 0 +@set PATCHLEVEL 1 @c added Italian hyphenation stuff @hyphenation{ven-go-no o-met-te-re o-met-ten-do} @@ -308,7 +308,7 @@ Some comments on the layout for TeX. Tel.: +1-617-542-5942 Fax: +1-617-542-2652 Email: <email>gnu@@gnu.org</email> URL: <ulink url="https://www.gnu.org">https://www.gnu.org/</ulink></literallayout> -<literallayout class="normal">Copyright © 1989, 1991, 1992, 1993, 1996–2005, 2007, 2009–2017 +<literallayout class="normal">Copyright © 1989, 1991, 1992, 1993, 1996–2005, 2007, 2009–2018 Free Software Foundation, Inc. All Rights Reserved. </literallayout> @@ -338,7 +338,8 @@ All Rights Reserved. @ifnotdocbook @iftex -Copyright @copyright{} 2017 -- Free Software Foundation, Inc. +Copyright @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2018 @* +Free Software Foundation, Inc. @end iftex @end ifnotdocbook @sp 2 @@ -422,7 +423,7 @@ URL: @uref{https://www.gnu.org/} @c This one is correct for gawk 3.1.0 from the FSF ISBN 1-882114-28-0 @sp 0 -Copyright @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2017 @* +Copyright @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2018 @* Free Software Foundation, Inc. @sp 1 Traduzione e revisione:@* @@ -508,7 +509,7 @@ Questo file documenta @command{awk}, un programma che si pu@`o usare per selezionare dei record determinati in un file ed eseguire azioni su di essi. @noindent -Copyright dell'edizione originale @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2017 @* +Copyright dell'edizione originale @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2018 @* Free Software Foundation, Inc. @noindent @@ -1207,7 +1208,6 @@ Copyright dell'edizione italiana @copyright{} 2016 -- Free Software Foundation, * Obiettivi delle estensioni:: Obiettivi del nuovo meccanismo. * Altre scelte progettuali per le estensioni:: Qualche altra scelta progettuale. * Futuri sviluppi delle estensioni:: Possibilit@`a di crescita futura. -* Meccanismo delle vecchie estensioni:: Problemi con le vecchie estensioni. * Sommario delle note:: Sommario delle note di implementazione. * Fondamenti ad alto livello:: Una visione dall'alto. @@ -1689,8 +1689,10 @@ del tipo: @example $ @kbd{awk 1 /dev/null} +@group @error{} awk: syntax error near line 1 @error{} awk: bailing out near line 1 +@end group @end example @noindent @@ -1948,6 +1950,7 @@ e alcune possibili direzioni per il futuro sviluppo di @command{gawk}. fornisce del materiale di riferimento a livello elementare per chi sia completamente digiuno di programmazione informatica. +@item Il @ref{Glossario}, definisce quasi tutti i termini significativi usati all'interno di questo @value{DOCUMENT}. Se si incontrano termini coi quali non si ha familiarit@`a, questo @`e il posto dove cercarli. @@ -2260,39 +2263,21 @@ di gestire una raccolta di programmi @command{awk} pubblicamente disponibili e avevo anche esortato a collaborare. Rendere disponibili le cose su Internet aiuta a contenere la distribuzione @command{gawk} entro dimensioni gestibili. -L'iniziale raccolta di materiale, come questo, @`e tuttora disponibile +L'iniziale raccolta di materiale, cos@`{@dotless{i}} com'@`e, @`e tuttora disponibile su @uref{ftp://ftp.freefriends.org/arnold/Awkstuff}. -Chi fosse @emph{seriamente} interessato a contribuire nell'implementazione -di un sito Internet dedicato ad argomenti riguardanti il -linguaggio @command{awk}, @`e pregato di contattarmi. - -@ignore -Nella speranza di -fare qualcosa di pi@`u esteso, acquisii il dominio @code{awk.info}. - -Tuttavia, mi accorsi che non potevo dedicare abbastanza tempo per la gestione -del codice inviato dai collaboratori: l'archivio non cresceva e il dominio -rimase in disuso per diversi anni. +Nella speranza di fare qualcosa di pi@`u generale, ho acuisito il dominio +@code{awklang.org}. A fine anno 2017 un volontario si @`e assunto il compito +di gestirlo. -Alla fine del 2008, un volontario si assunse il compito di mettere a punto -un sito web collegato ad @command{awk}---@uref{http://awk.info}---e fece un -lavoro molto ben fatto. +Se qualcuno ha scritto un programma @command{awk} interessante, o +un'estensione a @command{gawk} che vuole condividere col resto del mondo, +@`e invitato a consultare la pagina @uref{http://www.awklang.org} e a usare +il puntatore ``Contact''. -Se qualcuno ha scritto un programma @command{awk} interessante, o un'estensione -a @command{gawk} che vuole condividere col resto del mondo, @`e invitato a -consultare la pagina @uref{http://awk.info/?contribute} per sapere come -inviarlo per contribuire al sito web. +Se qualcuno ha scritto un'estensione a @command{gawk}, si veda +@ref{gawkextlib}. -Mentre scrivo, questo sito @`e in cerca di un responsabile; se qualcuno @`e -interessato mi contatti. -@end ignore - -@ignore -Altri collegamenti: - -https://www.reddit.com/r/linux/comments/dtect/composing_music_in_awk/ -@end ignore @end ifclear @node Ringraziamenti @@ -2914,6 +2899,8 @@ messaggio di errore di qualche tipo da @command{awk}. @cindex variabili @code{ARGC}/@code{ARGV}, portabilit@`a e @cindex portabilit@`a, variabile @code{ARGV} Infine, il valore di @code{ARGV[0]} +@cindex angolo buio, @code{ARGV}, valore della variabile +@cindex angolo buio, variabile @code{ARGV}, valore (@pxref{Variabili predefinite}) pu@`o variare a seconda del sistema operativo. Alcuni sistemi ci mettono @samp{awk}, altri il nome completo del percorso @@ -3180,10 +3167,12 @@ per i caratteri apice singolo e doppio, cos@`{@dotless{i}}: @example +@group $ @kbd{awk 'BEGIN @{ print "Questo @`e un apice singolo <\47>" @}'} @print{} Questo @`e un apice singolo <'> $ @kbd{awk 'BEGIN @{ print "Questo @`e un doppio apice <\42>" @}'} @print{} Questo @`e un doppio apice <"> +@end group @end example @noindent @@ -3470,8 +3459,10 @@ e non ha azione---quindi applica l'azione di default, stampando il record. Stampare la lunghezza della riga in input pi@`u lunga: @example +@group awk '@{ if (length($0) > max) max = length($0) @} END @{ print max @}' data +@end group @end example Il codice associato a @code{END} viene eseguito dopo che tutto @@ -3802,11 +3793,13 @@ un @samp{#} che inizia un commento, ignora @emph{tutto} il resto della riga. Per esempio: @example +@group $ @kbd{gawk 'BEGIN @{ print "Non allarmarti" # una amichevole \} > @kbd{ regola BEGIN} > @kbd{@}'} @error{} gawk: riga com.:2: regola BEGIN @error{} gawk: riga com.:2: ^ syntax error +@end group @end example @noindent @@ -3967,8 +3960,8 @@ riga di comando, sia quelle dello standard POSIX che quelle specifiche di argomenti che non sono opzioni. Prosegue poi spiegando come @command{gawk} cerca i file sorgenti, leggendo lo standard input assieme ad altri file, le variabili d'ambiente di -@command{gawk}, lo stato di ritorno di @command{gawk}, l'uso dei file inclusi, -e opzioni e/o funzionalit@`a obsolete e non documentate. +@command{gawk}, il codice di ritorno di @command{gawk}, l'uso dei file +inclusi, e opzioni e/o funzionalit@`a obsolete e non documentate. Molte delle opzioni e funzionalit@`a qui descritte sono trattate con maggior dettaglio nei capitoli successivi del @value{DOCUMENT}; gli argomenti @@ -4027,6 +4020,7 @@ awk '' file_dati_1 file_dati_2 @end example @cindex @option{--lint}, opzione +@cindex angolo buio, programmi vuoti @noindent Fare cos@`{@dotless{i}} ha comunque poco senso; @command{awk} termina silenziosamente quando viene fornito un programma vuoto. @@ -4269,7 +4263,7 @@ Quest'opzione @`e particolarmente necessaria per le applicazioni World Wide Web CGI che passano argomenti attraverso le URL; l'uso di quest'opzione impedisce a un utente malintenzionato (o ad altri) di passare opzioni, assegnamenti o codice sorgente @command{awk} (con @option{-e}) all'applicazione -CGI.@footnote{per maggiori dettagli, +CGI.@footnote{Per maggiori dettagli, si veda la Sezione 4.4 di @uref{http://www.ietf.org/rfc/rfc3875, RFC 3875}. Si veda anche @uref{https://lists.gnu.org/archive/html/bug-gawk/2014-11/msg00022.html, @@ -4424,12 +4418,10 @@ Ora non @`e pi@`u cos@`{@dotless{i}}. @cindex @option{--optimize}, opzione @cindex @option{-O}, opzione Abilita le ottimizzazioni di default nella rappresentazione interna del -programma. Attualmente, questo comprende delle semplificazioni nell'uso -di costanti e l'eliminazione delle code di chiamata nelle funzioni -ricorsive [sostituzione della chiamata di funzione con dei salti -diretti alla funzione]. +programma. Attualmente, questo comprende solo delle semplificazioni nell'uso +di costanti. -Queste ottimizzazioni sono abilitate per default. +Quest'ottimizzazione @`e abilitata per default. Quest'opzione rimane disponibile per compatibilit@`a all'indietro. Tuttavia pu@`o essere usata per annullare l'effetto di una precedente opzione @option{-s} (si veda pi@`u sotto in questa lista). @@ -4893,6 +4885,16 @@ essere di aiuto per gestire la variabile @env{AWKPATH}. @code{ENVIRON["AWKLIBPATH"]}. Questo consente di aver accesso al valore del percorso di ricerca in uso all'interno di un programma @command{awk}. +Sebbene sia possibile modificare la variabile @code{ENVIRON["AWKLIBPATH"]} +all'interno di un programma @command{awk}, la modifica non ha effetto +sul comportamento del programma in esecuzione. +Il motivo @`e chiaro: la variabile d'ambiente +@env{AWKLIBPATH} @`e usata per trovare eventuali estensioni richieste, e +queste sono caricate prima che il programma inizi l'esecuzione. Dopo che +il programma ha iniziato l'esecuzione, tutte le estensioni sono gi@`a state +caricate, e @command{gawk} non ha pi@`u bisogno di usare la variabile d'ambiente +@env{AWKLIBPATH}. + @node Altre variabili d'ambiente @subsection Le variabili d'ambiente. @@ -5086,10 +5088,12 @@ I file da includere possono essere nidificati; p.es., dato un terzo @dfn{script}, che chiameremo @file{test3}: @example +@group @@include "test2" BEGIN @{ print "Questo @`e lo script test3." @} +@end group @end example @noindent @@ -5187,8 +5191,10 @@ $ @kbd{gawk '@@load "ordchr"; BEGIN @{print chr(65)@}'} Questo equivale all'esempio seguente: @example +@group $ @kbd{gawk -lordchr 'BEGIN @{print chr(65)@}'} @print{} A +@end group @end example @noindent @@ -5317,6 +5323,14 @@ programmi erano stati scritti. Le funzioni predefinite standard di command{awk}, per esempio @code{sin()} o @code{substr()} @emph{non} ammettono questa possibilit@`a. +@`E possibile specificare in @code{printf} un modificatore @samp{P} +fra le lettere di controllo dei numeri in virgola mobile, per +utilizzare il risultato fornito dalle funzioni di libreria C +per i valori NaN [Not a Number] e Infinity [Infinito], invece dei +valori speciali normalmente prodotti da @command{gawk}, come +descritto in @ref{Problemi virgola mobile POSIX}. +Questo serve principalmente nella fase di test delle componenti aggiunte. + @end ignore @node Sommario invocazione @@ -5572,12 +5586,12 @@ Nuova pagina, @kbd{Ctrl-l}, codice ASCII 12 (FF). @cindex @code{\} (barra inversa), @code{\n}, sequenza di protezione @cindex barra inversa (@code{\}), @code{\n}, sequenza di protezione @item \n -A capo, @kbd{Ctrl-j}, codice ASCII 10 (LF). +A-capo, @kbd{Ctrl-j}, codice ASCII 10 (LF). @cindex @code{\} (barra inversa), @code{\r}, sequenza di protezione @cindex barra inversa (@code{\}), @code{\r}, sequenza di protezione @item \r -Ritorno del carrello, @kbd{Ctrl-m}, codice ASCII 13 (CR). +Ritorno-a-capo, @kbd{Ctrl-m}, codice ASCII 13 (CR). @cindex @code{\} (barra inversa), @code{\t}, sequenza di protezione @cindex barra inversa (@code{\}), @code{\t}, sequenza di protezione @@ -6088,8 +6102,7 @@ l'altro.) caratteri di controllo). @item @code{[:punct:]} @tab Caratteri di punteggiatura (caratteri che non sono lettere, cifre, caratteri di controllo, o caratteri di spazio). -@item @code{[:space:]} @tab Caratteri di spazio (come @dfn{spazio}, TAB, e -@dfn{formfeed}, per citarne alcuni). +@item @code{[:space:]} @tab Caratteri di spazio (ovvero: @dfn{spazio}, TAB, avanzamento riga (@dfn{newline}), ritorno a capo (@dfn{carriage return}), avanzamento pagina (@dfn{formfeed}) e tabulazione verticale) @item @code{[:upper:]} @tab Caratteri alfabetici maiuscoli. @item @code{[:xdigit:]} @tab Caratteri che sono cifre esadecimali. @end multitable @@ -6116,6 +6129,12 @@ dell'insieme di caratteri ASCII. Usando una lista di caratteri che esclude (@samp{[^\x00-\x7F]}) si individuano tutti i caratteri mono-byte che non sono nell'intervallo ASCII. +@quotation NOTA +Alcune vecchie versioni Unix di @command{awk} +trattano @code{[:blank:]} come @code{[:space:]}, individuando quindi +pi@`u caratteri del dovuto. Caveat Emptor! [Stia in guardia il compratore!]. +@end quotation + @cindex espressioni tra parentesi quadre, elementi di collazione @cindex espressioni tra parentesi quadre, non-ASCII @cindex elementi di collazione @@ -6296,8 +6315,8 @@ chiaramente che si vuole una corrispondenza con una @dfn{regexp}. @cindex ritorno a capo, in @dfn{regexp} dinamiche Alcune delle prime versioni di @command{awk} non consentono di usare il -carattere di ritorno -a capo all'interno di un'espressione tra parentesi quadre in @dfn{regexp} +carattere di ritorno a capo +all'interno di un'espressione tra parentesi quadre in @dfn{regexp} dinamiche: @example @@ -6733,6 +6752,14 @@ numero totale di record in input gi@`a letti da tutti i @value{DF}. Il suo valore iniziale @`e zero ma non viene mai reimpostata a zero automaticamente. +I record sono normalmente separati dal carattere di avanzamento riga +(@dfn{newline}). @`E possibile specificare come vanno separati i record +assegnando un valore alla variabile predefinita @code{RS}. +Se il valore di @code{RS} @`e costituto da un solo carattere, @`e quello +il carattere che fa da separatore fra i record. +Altrimenti (in @command{gawk}), @code{RS} @`e valutata come espressione +regolare. Questo meccanismo @`e spiegato pi@`u in dettaglio qui sotto. + @menu * awk divisione record:: Come @command{awk} standard divide i record. * gawk divisione record:: Come @command{gawk} divide i record. @@ -6777,13 +6804,16 @@ file in input, e la seconda regola nel programma @command{awk} (l'azione eseguita se non si specifica un criterio) stampa ogni record. Poich@'e ogni istruzione @code{print} aggiunge un ritorno a capo alla fine del suo output, questo programma -@command{awk} copia l'input con ogni @samp{u} trasformato in un ritorno -a capo. Qui vediamo il risultato dell'esecuzione del programma sul file +@command{awk} copia l'input con ogni @samp{u} trasformato in un +ritorno a capo. +Qui vediamo il risultato dell'esecuzione del programma sul file @file{mail-list}: @example +@group $ @kbd{awk 'BEGIN @{ RS = "u" @}} > @kbd{@{ print $0 @}' mail-list} +@end group @print{} Amelia 555-5553 amelia.zodiac @print{} sq @print{} e@@gmail.com F @@ -6860,6 +6890,14 @@ Usando un carattere insolito come @samp{/} @`e pi@`u probabile che si ottenga un comportamento corretto nella maggioranza dei casi, ma non c'@`e nessuna garanzia. La morale @`e: conosci i tuoi dati! +@command{gawk} consente di usare per @code{RS} un'espressione regolare +normale (descritta pi@`u avanti; @pxref{gawk divisione record}). +Tuttavia, se l'espressione regolare @`e costituita da un singolo metacarattere, +come p.es. @samp{.} che assegni il valore di @code{RS}, il metacarattere +in questione non viene trattato come tale, ma viene usato letteralmente. +Ci@`o viene fatto per compatibilit@`a all'indietro sia con il comando +Unix @command{awk} che con lo standard POSIX. + Quando si usano caratteri normali come separatore di record, c'@`e un caso insolito che capita quando @command{gawk} @`e reso completamente conforme a POSIX (@pxref{Opzioni}). @@ -6882,8 +6920,8 @@ Il raggiungimento della fine di un file in input fa terminare il record di input corrente, anche se l'ultimo carattere nel file non @`e il carattere in @code{RS}. @value{DARKCORNER} -@cindex stringhe vuote -@cindex stringhe nulle +@cindex stringa vuota +@cindex stringa nulla @c @cindex strings, empty, see null strings La stringa nulla @code{""} (una stringa che non contiene alcun carattere) ha un significato particolare come @@ -6914,7 +6952,8 @@ imposta la variabile @code{RT} al testo nell'input che corrisponde a @cindex comuni, estensioni@comma{} @code{RS} come espressione regolare Quando si usa @command{gawk}, il valore di @code{RS} non @`e limitato a una stringa costituita da un solo -carattere, ma pu@`o essere qualsiasi espressione regolare +carattere. Se contiene pi@`u di un carattere, @`e considerato essere +un'espressione regolare @iftex (@pxrefil{Espressioni regolari}). @value{COMMONEXT} @end iftex @@ -6945,9 +6984,11 @@ cerca sia un ritorno a capo che una serie di una o pi@`u lettere maiuscole con uno spazio vuoto opzionale iniziale e/o finale: @example +@group $ @kbd{echo record 1 AAAA record 2 BBBB record 3 |} > @kbd{gawk 'BEGIN @{ RS = "\n|( *[[:upper:]]+ *)" @}} > @kbd{@{ print "Record =", $0,"e RT = [" RT "]" @}'} +@end group @print{} Record = record 1 e RT = [ AAAA ] @print{} Record = record 2 e RT = [ BBBB ] @print{} Record = record 3 e RT = [ @@ -7325,6 +7366,8 @@ $ @kbd{echo a b c d e f | awk '@{ print "NF =", NF;} @quotation ATTENZIONE Alcune versioni di @command{awk} non ricostruiscono @code{$0} quando @code{NF} viene diminuito. +Fino ad agosto 2018, fra queste c'era BWK @command{awk}; per fortuna +da allora la sua versione funziona correttamente. @end quotation Infine, ci sono casi in cui conviene forzare @@ -7333,8 +7376,10 @@ dei campi e @code{OFS}. Per far ci@`o, si usa l'apparentemente innocuo assegnamento: @example +@group $1 = $1 # forza la ricostruzione del record print $0 # o qualsiasi altra cosa con $0 +@end group @end example @noindent @@ -7546,8 +7591,8 @@ $ @kbd{echo ' a b c d ' | awk 'BEGIN @{ FS = "[ \t\n]+" @}} @noindent @c @cindex null strings -@cindex stringhe nulle -@cindex stringhe vuote, si veda stringhe nulle +@cindex stringa nulla +@cindex stringa vuota, si veda stringa nulla In questo caso, il primo campo @`e nullo, o vuoto. Il taglio degli spazi vuoti iniziale e finale ha luogo anche ogniqualvolta @code{$0} @`e ricalcolato. @@ -8197,16 +8242,20 @@ e divide i dati: @example @c file eg/misc/simple-csv.awk +@group BEGIN @{ FPAT = "([^,]+)|(\"[^\"]+\")" @} +@end group +@group @{ print "NF = ", NF for (i = 1; i <= NF; i++) @{ printf("$%d = <%s>\n", i, $i) @} @} +@end group @c endfile @end example @@ -8270,14 +8319,6 @@ FPAT = "([^,]*)|(\"[^\"]+\")" Infine, la funzione @code{patsplit()} rende la stessa funzionalit@`a disponibile per suddividere normali stringhe (@pxref{Funzioni per stringhe}). -@ignore -Per ricapitolare, @command{gawk} fornisce tre metodi indipendenti per -suddividere in campi i record in input. -Il meccanismo usato @`e determinato da quella tra le tre -variabili---@code{FS}, @code{FIELDWIDTHS}, o @code{FPAT}---a cui -sia stato assegnato un valore pi@`u recentemente. -@end ignore - @node Controllare la creazione di campi @section Controllare come @command{gawk} sta dividendo i record @@ -8537,7 +8578,7 @@ e avere acquisito una buona conoscenza di come funziona @command{awk}. @cindex @command{gawk}, variabile @code{ERRNO} in @cindex @code{ERRNO}, variabile, con comando @command{getline} @cindex differenze tra @command{awk} e @command{gawk}, comando @code{getline} -@cindex @code{getline}, comando, valori di ritorno +@cindex @code{getline}, comando, codice di ritorno @cindex @option{--sandbox}, opzione, ridirezione dell'input con @code{getline} Il comando @code{getline} restituisce 1 se trova un record e 0 se @@ -8673,6 +8714,7 @@ e controlla ogni regola" non la veda affatto. L'esempio seguente inverte tra loro a due a due le righe in input: @example +@group @{ if ((getline tmp) > 0) @{ print tmp @@ -8680,6 +8722,7 @@ L'esempio seguente inverte tra loro a due a due le righe in input: @} else print $0 @} +@end group @end example @noindent @@ -8825,6 +8868,7 @@ sostituite dall'output prodotto dall'esecuzione del resto della riga costituito da un comando di shell. @example +@group @{ if ($1 == "@@execute") @{ tmp = substr($0, 10) # Rimuove "@@execute" @@ -8834,6 +8878,7 @@ costituito da un comando di shell. @} else print @} +@end group @end example @noindent @@ -9162,12 +9207,14 @@ specificato. Per esempio, un cliente TCP pu@`o decidere di abbandonare se non riceve alcuna risposta dal server dopo un certo periodo di tempo: @example +@group Service = "/inet/tcp/0/localhost/daytime" PROCINFO[Service, "READ_TIMEOUT"] = 100 if ((Service |& getline) > 0) print $0 else if (ERRNO != "") print ERRNO +@end group @end example Qui vediamo come ottenere dati interattivamente dall'utente@footnote{Questo @@ -9202,7 +9249,7 @@ messaggio di errore: @example @c questo @`e l'output effettivo - Antonio -@error{} gawk: linea com.:2: (FILENAME=- FNR=1) fatale: errore leggendo +@error{} gawk: riga com.:2: (FILENAME=- FNR=1) fatale: errore leggendo @error{} file in input `-': Connessione scaduta @end example @@ -9478,8 +9525,8 @@ L'istruzione @code{print} si usa per produrre dell'output formattato in maniera semplice, standardizzata. Si specificano solo le stringhe o i numeri da stampare, in una lista separata da virgole. Questi elementi sono stampati, -separati tra loro da spazi singoli, e alla fine viene stampato un ritorno a -capo. L'istruzione @`e simile a questa: +separati tra loro da spazi singoli, e alla fine viene stampato un +ritorno a capo. L'istruzione @`e simile a questa: @example print @var{elemento1}, @var{elemento2}, @dots{} @@ -9542,10 +9589,12 @@ ritorni a capo: @end ifnotinfo @example +@group $ @kbd{awk 'BEGIN @{ print "riga uno\nriga due\nriga tre" @}'} @print{} riga uno @print{} riga due @print{} riga tre +@end group @end example @cindex campi, stampare @@ -9751,7 +9800,7 @@ $ @kbd{awk 'BEGIN @{} @cindex variabile @code{OFMT}, POSIX @command{awk} e Per lo standard POSIX, il comportamento di @command{awk} @`e indefinito se @code{OFMT} contiene qualcosa di diverso da una specifica di conversione -di un numero a virgola mobile. +di un numero in virgola mobile. @value{DARKCORNER} @node Printf @@ -9819,12 +9868,14 @@ effetto sulle istruzioni @code{printf}. Per esempio: @example +@group $ @kbd{awk 'BEGIN @{} > @kbd{ORS = "\nAHI!\n"; OFS = "+"} > @kbd{msg = "Non v\47allarmate!"} > @kbd{printf "%s\n", msg} > @kbd{@}'} @print{} Non v'allarmate! +@end group @end example @noindent @@ -9848,6 +9899,29 @@ lettere di controllo del formato: @c @asis for docbook to come out right @table @asis +@item @code{%a}, @code{%A} +Un numero in virgola mobile scritto nella forma +[@code{-}]@code{0x@var{h}.@var{hhhh}p+-@var{dd}} +(formato esadecimale virgola mobile nel compilatore C99). +Per @code{%A}, +si usano lettere maiuscole invece che lettere minuscole. + +@quotation NOTA +Lo standard POSIX in vigore richiede il supporto di @code{%a} +e di @code{%A} in @command{awk}. Per quanto ci consta, oltre a +@command{gawk}, la sola altra versione di @command{awk} che fornisce +questo supporto @`e BWK @command{awk}. +Se si usano questi formati, il programma in questione @`e quindi +estremamente non-portabile! + +Inoltre, questi formati non sono disponibili su alcun sistema in cui +la funzione di libreria C @code{printf()} utilizzata da @command{gawk} +non li supporta. +Al momento in cui questo libro @`e stato scritto, fra i sistemi su cui +@`e stato portato @command{gawk}, il solo sistema noto che +non li supporta @`e OpenVMS. +@end quotation + @item @code{%c} Stampa un numero come un carattere; quindi, @samp{printf "%c", 65} stampa la lettera @samp{A}. L'output per un valore costituito da una @@ -9870,6 +9944,7 @@ carattere da stampare. Altre versioni di @command{awk} generalmente si limitano a stampare il primo byte di una stringa o i valori numerici che possono essere rappresentati in un singolo byte (0--255). +@value{DARKCORNER} @end quotation @@ -9896,7 +9971,7 @@ introdotti nella prossima @value{SUBSECTION}). @samp{%E} usa @samp{E} invece di @samp{e} nell'output. @item @code{%f} -Stampa un numero in notazione a virgola mobile. +Stampa un numero in notazione in virgola mobile. Per esempio: @example @@ -9909,7 +9984,7 @@ delle quali vengono dopo il punto decimale. (L'espressione @samp{4.3} rappresenta due modificatori, introdotti nella prossima @value{SUBSECTION}). -In sistemi che implementano il formato a virgola mobile, come specificato +In sistemi che implementano il formato in virgola mobile, come specificato dallo standard IEEE 754, il valore infinito negativo @`e rappresentato come @samp{-inf} o @samp{-infinity}, e l'infinito positivo come @@ -9927,7 +10002,7 @@ i sistemi lo prevedono. In tali casi, @command{gawk} usa il formato @samp{%f}. @item @code{%g}, @code{%G} -Stampa un numero usando o la notazione scientifica o quella a virgola +Stampa un numero usando o la notazione scientifica o quella in virgola mobile, scegliendo la forma pi@`u concisa; se il risultato @`e stampato usando la notazione scientifica, @samp{%G} usa @samp{E} invece di @samp{e}. @@ -9941,7 +10016,7 @@ Stampa una stringa. @item @code{%u} Stampa un numero intero decimale, senza segno. (Questo formato @`e poco usato, perch@'e tutti i numeri in @command{awk} -sono a virgola mobile; @`e disponibile principalmente per compatibilit@`a col +sono in virgola mobile; @`e disponibile principalmente per compatibilit@`a col linguaggio C.) @item @code{%x}, @code{%X} @@ -9970,6 +10045,18 @@ stampare valori non validi, o comportarsi in modo completamente differente. @value{DARKCORNER} @end quotation +@quotation NOTA +Lo standard IEEE 754 per l'aritmetica in virgola mobile consente di +avere valori speciali per rappresentare ``infinito'' (sia positivo che +negativo) e valori che sono ``non numerici'' (NaN - [Not a Number]). + +L'input e l'output di tali valori avviene sotto forma di stringhe di +testo. Ci@`o pone dei problemi nel linguaggio @command{awk}, che +esisteva gi@`a prima della definizione dello standard IEEE. Dettagli +ulteriori si possono trovare in @ref{Problemi virgola mobile POSIX}; +si prega di fare riferimento a quel testo. +@end quotation + @node Modificatori di formato @subsection Modificatori per specifiche di formato @code{printf} @@ -10061,7 +10148,7 @@ di quella del valore da stampare. @item @code{'} Un carattere di apice singolo o un apostrofo @`e un'estensione POSIX allo standard ISO C. -Indica che la parte intera di un valore a virgola mobile, o la parte intera +Indica che la parte intera di un valore in virgola mobile, o la parte intera di un valore decimale intero, ha un carattere di separazione delle migliaia. Ci@`o @`e applicabile solo alle localizzazioni che prevedono un tale carattere. Per esempio: @@ -10386,9 +10473,11 @@ alone for now and let's hope no-one notices. @end ignore @example +@group awk '@{ print $1 > "nomi.non.ordinati" comando = "sort -r > nomi.ordinati" print $1 | comando @}' mail-list +@end group @end example La lista non ordinata @`e scritta usando una ridirezione normale, mentre @@ -10703,12 +10792,12 @@ Questo avviene usando uno speciale @value{FN} della forma: @file{/@var{tipo-rete}/@var{protocollo}/@var{porta-locale}/@var{host-remoto}/@var{porta-remota}} @end example -il @var{tipo-rete} pu@`o essere @samp{inet}, @samp{inet4} o @samp{inet6}. +Il @var{tipo-rete} pu@`o essere @samp{inet}, @samp{inet4} o @samp{inet6}. Il @var{protocollo} pu@`o essere @samp{tcp} o @samp{udp}, e gli altri campi rappresentano gli altri dati essenziali necessari per realizzare una connessione di rete. Questi @value{FNS} sono usati con l'operatore @samp{|&} per comunicare -con un coprocesso +con @w{un coprocesso} (@pxref{I/O bidirezionale}). Questa @`e una funzionalit@`a avanzata, qui riferita solo per completezza. Una spiegazione esauriente sar@`a fornita nella @@ -10811,10 +10900,14 @@ essere uguale all'espressione usata per aprire il file o eseguire il comando, Il precedente esempio cambia come segue: @example +@group sortcom = "sort -r nomi" sortcom | getline pippo +@end group +@group @dots{} close(sortcom) +@end group @end example @noindent @@ -10902,7 +10995,7 @@ per la @dfn{pipe} non @`e chiuso e liberato finch@'e non si chiama @code{close()} non fa nulla (e non emette messaggi) se le viene fornito come argomento una stringa che non rappresenta un file, una @dfn{pipe} o un coprocesso che sia stato aperto mediante una ridirezione. In quel caso, -@code{close()} restituisce un valore di ritorno negativo, che indica un +@code{close()} restituisce un codice di ritorno negativo, che indica un errore. Inoltre, @command{gawk} imposta @code{ERRNO} a una stringa che indica il tipo di errore. @@ -10928,19 +11021,19 @@ rinviata alla @ref{I/O bidirezionale}, che ne parla pi@`u dettagliatamente e fornisce un esempio. -@sidebar Usare il valore di ritorno di @code{close()} +@sidebar Usare il codice di ritorno di @code{close()} @cindex angolo buio, funzione @code{close()} -@cindex funzione @code{close()}, valore di ritorno -@cindex @code{close()}, funzione, valore di ritorno -@cindex valore di ritorno@comma{} funzione @code{close()} +@cindex funzione @code{close()}, codice di ritorno +@cindex @code{close()}, funzione, codice di ritorno +@cindex codice di ritorno@comma{} funzione @code{close()} @cindex differenze tra @command{awk} e @command{gawk}, funzione @code{close()} @cindex Unix @command{awk}, funzione @code{close()} e In molte versioni di Unix @command{awk}, la funzione @code{close()} @`e in realt@`a un'istruzione. @value{DARKCORNER} -@`E un errore di sintassi tentare di usare il valore -di ritorno da @code{close()}: +@`E un errore di sintassi tentare di usare il +codice di ritorno da @code{close()}: @example comando = "@dots{}" @@ -10952,7 +11045,7 @@ retval = close(comando) # errore di sintassi in parecchi Unix awk @cindex variabile @code{ERRNO}, con funzione @command{close()} @cindex @code{ERRNO}, variabile, con funzione @command{close()} @command{gawk} gestisce @code{close()} come una funzione. -Il valore di ritorno @`e @minus{}1 se l'argomento designa un file +Il codice di ritorno @`e @minus{}1 se l'argomento designa un file che non era mai stato aperto con una ridirezione, o se c'@`e un problema di sistema nella chiusura del file o del processo. In tal caso, @command{gawk} imposta la variabile predefinita @@ -10960,18 +11053,18 @@ In tal caso, @command{gawk} imposta la variabile predefinita In @command{gawk}, a partire dalla @value{PVERSION} 4.2, quando si chiude una @dfn{pipe} o un coprocesso (in input o in output), -il valore di ritorno @`e quello restituito dal comando, +il codice di ritorno @`e quello restituito dal comando, come descritto in @ref{table-close-pipe-return-values}.@footnote{Prima -della @value{PVERSION} 4.2, il valore di ritorno dopo la chiusura di +della @value{PVERSION} 4.2, il codice di ritorno dopo la chiusura di una @dfn{pipe} o di un coprocesso era una cifra di due byte (16-bit), contenente il valore restituito dalla chiamata di sistema @code{wait()}}. -Altrimenti, @`e il valore di ritorno dalla chiamata alle funzione +Altrimenti, @`e il codice di ritorno dalla chiamata alle funzione di sistema @code{close()} o alla funzione C @code{fclose()} se si sta chiudendo un file in input o in output, rispettivamente. Questo valore @`e zero se la chiusura riesce, o @minus{}1 se non riesce. @float Tabella,table-close-pipe-return-values -@caption{Valori di ritorno dalla @code{close()} di una @dfn{pipe}} +@caption{Codici di ritorno dalla @code{close()} di una @dfn{pipe}} @multitable @columnfractions .50 .50 @headitem Situazione @tab Valore restituito da @code{close()} @item Uscita normale dal comando @tab Il codice di ritorno del comando @@ -10985,7 +11078,7 @@ Lo standard POSIX @`e molto generico; dice che @code{close()} restituisce zero se @`e terminata correttamente, e un valore diverso da zero nell'altro caso. In generale, implementazioni differenti variano in quel che restituiscono chiudendo una -@dfn{pipe}; quindi, il valore di ritorno non pu@`o essere usato in modo +@dfn{pipe}; quindi, il codice di ritorno non pu@`o essere usato in modo portabile. @value{DARKCORNER} In modalit@`a POSIX (@pxref{Opzioni}), @command{gawk} restituisce solo zero @@ -11253,6 +11346,77 @@ tutti i possibili caratteri ASCII a otto bit, compreso il carattere ASCII Altre implementazioni di @command{awk} possono avere difficolt@`a con alcuni particolari codici di carattere. +Alcuni linguaggi di programmazione consentono la continuazione di stringhe +lunghe su pi@`u righe, qualora una riga termini con una barra inversa. +Per esempio in C: + +@example +#include <stdio.h> + +int main() +@{ + printf "ciao, \ +mondo\n"); + return 0; +@} +@end example + +@noindent +In questo caso, il compilatore C rimuove sia la barra inversa che il +carattere di avanzamento riga (@dfn{newline}), +producendo una stringa che equivale ad aver immesso +@samp{"ciao, mondo\n"}. Ci@`o torna utile quando una stringa deve contenere +una grande quantit@`a di testo. + +Lo standard POSIX afferma esplicitamente che +il carattere di avanzamento riga +non @`e consentito all'interno di costanti di tipo stringa. +E in effetti, tutte le implementazioni di @command{awk} emettono un +messaggio di errore se si tenta di utilizzarlo. Per esempio: + +@example +$ @kbd{gawk 'BEGIN @{ print "ciao, } +> @kbd{mondo" @}'} +@print{} gawk: riga com.:1: BEGIN @{ print "ciao, +@print{} gawk: riga com.:1: ^ stringa non terminata +@print{} gawk: riga com.:1: BEGIN @{ print "ciao, +@print{} gawk: riga com.:1: ^ syntax error +@end example + +@cindex angolo buio, stringhe, continuazione su pi@`u righe +@cindex stringhe, continuazione su pi@`u righe +@cindex differenze tra @command{awk} e @command{gawk}, stringhe +Sebbene POSIX non definisca cosa succede usando un carattere +protetto di avanzamento riga, come nell'esempio in linguaggio C +visto sopra, tutte le versioni di @command{awk} consentono di +farlo. Sfortunatamente, quello che una particolare versione di +@command{awk} fa con una tale stringa non @`e uniforme. +@value{DARKCORNER} @command{gawk}, @command{mawk}, e +OpenSolaris POSIX @command{awk} (@pxref{Altre versioni}) +tolgono sia la barra inversa che il carattere di +avanzamento riga, come avviene nel linguaggio C: + +@example +$ @kbd{gawk 'BEGIN @{ print "ciao, \} +> @kbd{mondo" @}'} +@print{} ciao, mondo +@end example + +In modalit@`a POSIX (@pxref{Opzioni}), @command{gawk} non consente +caratteri protetti di avanzamento riga. Altrimenti, il +comportamento @`e quello descritto sopra. + +BKW @command{awk} e Busybox @command{awk} +tolgono la barra inversa, ma lasciano indisturbato il carattere +di avanzamento riga, che fa quindi parte della stringa: + +@example +$ @kbd{nawk 'BEGIN @{ print "ciao, \} +> @kbd{mondo" @}'} +@print{} ciao, +@print{} mondo +@end example + @node Numeri non-decimali @subsubsection Numeri ottali ed esadecimali @cindex ottali, numeri @@ -11486,6 +11650,7 @@ argomenti di funzioni definite dall'utente (@pxref{Funzioni definite dall'utente}). Per esempio: @example +@group function mysub(modello, sostituzione, stringa, globale) @{ if (globale) @@ -11494,13 +11659,16 @@ function mysub(modello, sostituzione, stringa, globale) sub(modello, sostituzione, stringa) return stringa @} +@end group +@group @{ @dots{} text = "salve! salve a te!" mysub(/salve/, "ciao", text, 1) @dots{} @} +@end group @end example @c @cindex automatic warnings @@ -11757,6 +11925,25 @@ sequenze di protezione (@pxref{Sequenze di protezione}). @value{DARKCORNER} +Le variabili assegnate sulla riga di comando (sia tramite l'opzione +@option{-v} che senza) sono trattate come stringhe. Quando tali variabili +sono usate come numeri, viene effettuata la normale conversione automatica +da stringhe a numeri, e ogni cosa ``funziona come deve''. + +Peraltro, @command{gawk} supporta variabili di tipo ``regexp''. +Si possono assegnare valori a variabili di questo tipo usando la +sintassi seguente: + +@example +gawk -v 're1=@/pippo|pluto/' '@dots{}' /percorso/al/file1 're2=@/ciao|salve/' /percorso/al/file2 +@end example + +@noindent +Le costanti @dfn{regexp} fortemente tipizzate sono un'altra +funzionalit@`a avanzata disponibile +(@pxref{costanti @dfn{regexp} fortemente tipizzate}). +Sono ricordate qui solo per completezza. + @node Conversione @subsection Conversione di stringhe e numeri @@ -11786,8 +11973,10 @@ Se in una concatenazione di stringhe ci sono valori numerici, questi sono convertiti in stringhe. Si consideri il seguente esempio: @example +@group due = 2; tre = 3 print (due tre) + 4 +@end group @end example @noindent @@ -11796,7 +11985,7 @@ variabili @code{due} e @code{tre} sono convertiti in stringhe e concatenati insieme. La stringa risultante @`e riconvertita nel numero 23, al quale poi viene aggiunto 4. -@cindex stringhe nulle, conversione da tipo numerico a tipo stringa +@cindex stringa nulla, conversione da tipo numerico a tipo stringa @cindex conversione di tipo variabile @cindex variabile, conversione di tipo Se, per qualche ragione, si vuole forzare la conversione di un numero in @@ -11935,8 +12124,8 @@ ancora descritte. Infine, gli standard ufficiali correnti e la rappresentazione dei numeri in virgola mobile dello standard IEEE possono avere un effetto insolito ma importante sul modo in cui @command{gawk} converte alcuni valori di stringa -speciali in -numeri. I dettagli sono illustrati in @ref{Problemi virgola mobile POSIX}. +speciali in numeri. I dettagli sono illustrati in +@ref{Problemi virgola mobile POSIX}. @node Tutti gli operatori @section Operatori: fare qualcosa coi valori @@ -12129,8 +12318,8 @@ print "qualcosa di significativo" > nome file @cindex programma di utilit@`a @command{mawk} @noindent Questo produce un errore di sintassi in alcune versioni di -@command{awk} per Unix.@footnote{Pu@`o capitare che BWK -@command{awk}, @command{gawk} e @command{mawk} lo interpretino nel modo giusto, +@command{awk} per Unix.@footnote{Pu@`o capitare che BWK @command{awk}, +@command{gawk} e @command{mawk} lo interpretino nel modo giusto, ma non ci si dovrebbe fare affidamento.} @`E necessario usare la seguente sintassi: @@ -12288,10 +12477,14 @@ assegnato per ultimo. Nel seguente frammento di programma, la variabile @code{pippo} ha dapprima un valore numerico, e in seguito un valore di stringa: @example +@group pippo = 1 print pippo +@end group +@group pippo = "pluto" print pippo +@end group @end example @noindent @@ -12364,16 +12557,20 @@ di sinistra nell'espressione di destra. Per esempio: @cindex Rankin, Pat @example +@group # Grazie a Pat Rankin per quest'esempio BEGIN @{ pippo[rand()] += 5 for (x in pippo) print x, pippo[x] - +@end group + +@group pluto[rand()] = pluto[rand()] + 5 for (x in pluto) print x, pluto[x] @} +@end group @end example @cindex operatori di assegnamento, ordine di valutazione @@ -13073,10 +13270,12 @@ omettendo uno dei due caratteri @samp{=}. Il risultato @`e sempre un codice @command{awk} valido, ma il programma non fa quel che si voleva: @example +@group if (a = b) # oops! dovrebbe essere == b @dots{} else @dots{} +@end group @end example @noindent @@ -13525,7 +13724,7 @@ a un secondo momento; si veda @ref{Chiamate indirette}. @cindex effetti collaterali, chiamate di funzione Come ogni altra espressione, la chiamata di funzione ha un valore, chiamato spesso @dfn{valore di ritorno}, che @`e calcolato dalla funzione -in base agli argomenti dati. In quest'esempio, il valore di ritorno +in base agli argomenti dati. In quest'esempio, il codice di ritorno di @samp{sqrt(@var{argomento})} @`e la radice quadrata di @var{argomento}. Il seguente programma legge numeri, un numero per riga, e stampa la radice quadrata di ciascuno: @@ -14079,8 +14278,10 @@ $ @kbd{awk '! /li/' mail-list} @print{} Bill 555-1675 bill.drowning@@hotmail.com A @print{} Camilla 555-2912 camilla.infusarum@@skynet.be R @print{} Fabius 555-1234 fabius.undevicesimus@@ucb.edu F +@group @print{} Martin 555-6480 martin.codicibus@@hotmail.com A @print{} Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R +@end group @end example @cindex @code{BEGIN}, criterio di ricerca, criteri di ricerca booleani e @@ -14200,6 +14401,7 @@ $ @kbd{echo Yes | gawk '(/1/,/2/) || /Yes/'} @end example @cindex intervalli di ricerca, continuazione di riga e +@cindex angolo buio, intervalli di ricerca, continuazione di riga e Come punto di secondaria importanza, nonostante sia stilisticamente poco elegante, lo standard POSIX consente di andare a capo dopo la virgola in un intervallo di ricerca. @value{DARKCORNER} @@ -14515,10 +14717,12 @@ variabile nel progamma @command{awk} contenuto nello @dfn{script}: Per esempio, si consideri il programma seguente: @example +@group printf "Immettere il criterio di ricerca: " read criterio_di_ricerca awk "/$criterio_di_ricerca/ "'@{ num_trov++ @} END @{ print num_trov, "occorrenze trovate" @}' /nome/file/dati +@end group @end example @noindent @@ -14734,10 +14938,12 @@ la stringa nulla; altrimenti, la condizione @`e vera. Si consideri quanto segue: @example +@group if (x % 2 == 0) print "x @`e pari" else print "x @`e dispari" +@end group @end example In questo esempio, se l'espressione @samp{x % 2 == 0} @`e vera (cio@`e, @@ -14916,8 +15122,8 @@ awk ' @end example @noindent -Questo programma stampa i primi tre campi di ogni record in input, mettendo -un campo su ogni riga. +Questo programma stampa i primi tre campi di ogni record in input, +mettendo un unico campo in una riga in output. Non @`e possibile impostare pi@`u di una variabile nella parte di @@ -15089,6 +15295,7 @@ trova, se esiste, il divisore pi@`u piccolo di un dato numero intero, oppure dichiara che si tratta di un numero primo: @example +@group # trova il divisore pi@`u piccolo di num @{ num = $1 @@ -15096,11 +15303,14 @@ dichiara che si tratta di un numero primo: if (num % divisore == 0) break @} +@end group +@group if (num % divisore == 0) printf "Il pi@`u piccolo divisore di %d @`e %d\n", num, divisore else printf "%d @`e un numero primo\n", num @} +@end group @end example Quando il resto della divisione @`e zero nella prima istruzione @code{if}, @@ -15424,7 +15634,7 @@ viene specificato alcun argomento, Nel caso in cui un argomento sia specificato in una prima istruzione @code{exit} e poi @code{exit} sia chiamato una seconda volta all'interno di una regola @code{END} senza alcun -argomento, @command{awk} usa il valore di ritorno specificato in precedenza. +argomento, @command{awk} usa il codice di ritorno specificato in precedenza. @value{DARKCORNER} @xref{Codice di ritorno} per maggiori informazioni. @@ -15436,14 +15646,18 @@ segnalano terminando con un codice di ritorno diverso da zero. Un programma diverso da zero, come mostrato nell'esempio seguente: @example +@group BEGIN @{ if (("date" | getline data_corrente) <= 0) @{ print "Non riesco a ottenere la data dal sistema" > "/dev/stderr" exit 1 @} +@end group +@group print "la data corrente @`e", data_corrente close("date") @} +@end group @end example @quotation NOTA @@ -15705,7 +15919,7 @@ il carattere di ritorno a capo. @cindex @code{PREC}, variabile @cindex variabile @code{PREC} @item PREC # -La precisione disponibile nei numeri a virgola mobile a precisione arbitraria, +La precisione disponibile nei numeri in virgola mobile a precisione arbitraria, per default 53 bit (@pxref{Impostare la precisione}). @cindex @code{ROUNDMODE}, variabile @@ -15798,6 +16012,7 @@ A differenza di quasi tutti i vettori di @command{awk}, Lo si pu@`o vedere nell'esempio seguente: @example +@group $ @kbd{awk 'BEGIN @{} > @kbd{for (i = 0; i < ARGC; i++)} > @kbd{print ARGV[i]} @@ -15805,6 +16020,7 @@ $ @kbd{awk 'BEGIN @{} @print{} awk @print{} inventory-shipped @print{} mail-list +@end group @end example @noindent @@ -16003,7 +16219,7 @@ sono sicuramente sempre disponibili: @table @code @item PROCINFO["argv"] -@cindex argomenti, riga di comando, @code{PROCINFO["argv"} +@cindex argomenti, riga di comando, @code{PROCINFO["argv"]} Il vettore @code{PROCINFO["argv"]} contiene tutti gli argomenti della riga di comando (dopo che l'eventuale elaborazione di valutazione e ridirezione, nelle piattaforme in cui ci@`o debba essere fatto a cura del programma), con @@ -16084,6 +16300,31 @@ I valori riportano ci@`o che @command{gawk} sa sugli identificativi dopo aver finito l'analisi iniziale del programma; questi valori @emph{non} vengono pi@`u aggiornati durante l'esecuzione del programma. +@item PROCINFO["platform"] +@cindex piattaforma di esecuzione, @code{PROCINFO["platform"]} +Quest'elemento restituisce una stringa che indica la piattaforma +per la quale @command{gawk} @`e stato compilato. Il valore sar@`a +uno dei seguenti: + +@c nested table +@table @code +@item "vms" +OpenVMS o Vax/VMS. + +@item "djgpp" +@itemx "mingw" +Microsoft Windows, utilizzando DJGPP o MinGW, rispettivamente. + +@item "os2" +OS/2. + +@item "os390" +OS/390. + +@item "posix" +GNU/Linux, Cygwin, Mac OS X, e sistemi Unix tradizionali. +@end table + @item PROCINFO["pgrpid"] @cindex @dfn{process group ID} del programma @command{gawk} Il @dfn{ID di gruppo del processo} del programma corrente. @@ -16165,17 +16406,17 @@ gruppi supplementari che il processo [Unix] possiede. Si usi l'operatore I seguenti elementi consentono di modificare il comportamento di @command{gawk}: +@table @code @item PROCINFO["NONFATAL"] Se questo elemento esiste, gli errori di I/O per tutte le ridirezioni -consentono la prosecuzizone del programma. +consentono la prosecuzione del programma. @xref{Continuazione dopo errori}. -@item PROCINFO["@var{nome_output}", "NONFATAL"] -Gli errori in output per il file @var{nome_output} -consentono la prosecuzizone del programma. +@item PROCINFO["@var{nome}", "NONFATAL"] +Gli errori di I/O per il file @var{nome} +consentono la prosecuzione del programma. @xref{Continuazione dopo errori}. -@table @code @item PROCINFO["@var{comando}", "pty"] Per una comunicazione bidirezionale con @var{comando}, si usi una pseudo-tty invece di impostare una @dfn{pipe} bidirezionale. @@ -16186,7 +16427,7 @@ Imposta un tempo limite per leggere dalla ridirezione di input @var{input_name}. @xref{Timeout in lettura} per ulteriori informazioni. @item PROCINFO["@var{input_name}", "RETRY"] -Se durante la lettura del file @var{input_name}si verifica un errore di I/O +Se durante la lettura del file @var{input_name} si verifica un errore di I/O per il quale si pu@`o ritentare una lettura, e questo elemento di vettore esiste, @code{getline} d@`a come codice di ritorno @minus{}2 invece di seguire il comportamento di default, che consiste nel restituire @minus{}1 @@ -16205,7 +16446,7 @@ l'ordine in cui gli indici dei vettori saranno elaborati nei cicli @samp{for (@var{indice} in @var{vettore})}. Questa @`e una funzionalit@`a avanzata, la cui descrizione completa sar@`a vista pi@`u avanti; si veda -@ref{Visitare un intero vettore}. +@ref{Controllare visita}. @end table @cindex @code{RLENGTH}, variabile @@ -16265,7 +16506,8 @@ controllare se un elemento in @code{SYMTAB} @`e un vettore. Inoltre, non @`e possibile usare l'istruzione @code{delete} con il vettore @code{SYMTAB}. -@`E possibile aggiungere a @code{SYMTAB} un elemento che non sia un +Prima della @value{PVERSION} 5.0 di @command{gawk}, era possibile +usare come indice per @code{SYMTAB} una stringa che non era un identificativo gi@`a esistente: @example @@ -16274,9 +16516,8 @@ print SYMTAB["xxx"] @end example @noindent -Il risultato @`e quello previsto: in questo caso @code{SYMTAB} si comporta -come un normale vettore. La sola differenza @`e che non @`e poi possibile -cancellare @code{SYMTAB["xxx"]}. +Ci@`o non @`e pi@`u possibile, e il farlo determina un errore +fatale, perch@'e il poterlo fare era solo fonte di confusione. @cindex Schorr, Andrew Il vettore @code{SYMTAB} @`e pi@`u interessante di quel che sembra. Andrew @@ -16284,6 +16525,7 @@ Schorr fa notare che effettivamente consente di ottenere dei puntatori ai dati in @command{awk}. Si consideri quest'esempio: @example +@group # Moltiplicazione indiretta di una qualsiasi variabile per un # numero a piacere e restituzione del risultato @@ -16291,6 +16533,7 @@ function multiply(variabile, numero) @{ return SYMTAB[variabile] *= numero @} +@end group @end example @noindent @@ -16369,6 +16612,7 @@ conteneva il programma seguente che visualizzava le informazioni contenute in @code{ARGC} e @code{ARGV}: @example +@group $ @kbd{awk 'BEGIN @{} > @kbd{for (i = 0; i < ARGC; i++)} > @kbd{print ARGV[i]} @@ -16376,13 +16620,15 @@ $ @kbd{awk 'BEGIN @{} @print{} awk @print{} inventory-shipped @print{} mail-list +@end group @end example @noindent In questo esempio, @code{ARGV[0]} contiene @samp{awk}, @code{ARGV[1]} contiene @samp{inventory-shipped} e @code{ARGV[2]} contiene @samp{mail-list}. -Si noti che il nome del programma @command{awk} non @`e incluso in @code{ARGV}. +Si tenga presente che il nome del programma @command{awk} +non @`e incluso in @code{ARGV}. Le altre opzioni della riga di comando, con i relativi argomenti, sono parimenti non presenti, compresi anche gli assegnamenti di variabile fatti tramite l'opzione @option{-v} @@ -17001,8 +17247,10 @@ Per esempio, quest'istruzione verifica se il vettore @code{frequenze} contiene l'indice @samp{2}: @example +@group if (2 in frequenze) print "L'indice 2 @`e presente." +@end group @end example Si noti che questo @emph{non} verifica se il vettore @@ -17012,8 +17260,10 @@ elementi. Inoltre, questo @emph{non} crea @code{frequenze[2]}, mentre la seguente alternativa (non corretta) lo fa: @example +@group if (frequenze[2] != "") print "L'indice 2 @`e presente." +@end group @end example @node Impostare elementi @@ -17071,6 +17321,7 @@ stampare tutte le righe. Quando questo programma viene eseguito col seguente input: @example +@group @c file eg/misc/arraymax.data 5 Io sono l'uomo Cinque 2 Chi sei? Il nuovo numero due! @@ -17078,17 +17329,20 @@ Quando questo programma viene eseguito col seguente input: 1 Chi @`e il numero uno? 3 Sei il tre. @c endfile +@end group @end example @noindent Il suo output @`e: @example +@group 1 Chi @`e il numero uno? 2 Chi sei? Il nuovo numero due! 3 Sei il tre. 4 . . . E quattro a terra 5 Io sono l'uomo Cinque +@end group @end example Se un numero di riga appare pi@`u di una volta, l'ultima riga con quel dato @@ -17098,11 +17352,13 @@ si possono saltare con un semplice perfezionamento della regola @code{END} del programma, in questo modo: @example +@group END @{ for (x = 1; x <= massimo; x++) if (x in vett) print vett[x] @} +@end group @end example @node Visitare un intero vettore @@ -17123,8 +17379,10 @@ fare da indice in un vettore. Perci@`o @command{awk} ha un tipo speciale di istruzione @code{for} per visitare un vettore: @example +@group for (@var{variabile} in @var{vettore}) @var{corpo} +@end group @end example @noindent @@ -17147,12 +17405,15 @@ anche il numero di tali parole. per maggiori informazioni sulla funzione predefinita @code{length()}. @example +@group # Registra un 1 per ogni parola usata almeno una volta @{ for (i = 1; i <= NF; i++) usate[$i] = 1 @} +@end group +@group # Trova il numero di parole distinte lunghe pi@`u di 10 caratteri END @{ for (x in usate) @{ @@ -17163,6 +17424,7 @@ END @{ @} print numero_parole_lunghe, "parole pi@`u lunghe di 10 caratteri" @} +@end group @end example @noindent @@ -17571,9 +17833,11 @@ che assegnargli un valore nullo (la stringa vuota, @code{""}). Per esempio: @example +@group pippo[4] = "" if (4 in pippo) - print "Questo viene stampato, anche se pippo[4] @`e vuoto" + print "Questa riga viene stampata, anche se pippo[4] @`e vuoto" +@end group @end example @cindex @dfn{lint}, controlli, elementi di vettori @@ -17734,22 +17998,26 @@ END @{ Dato l'input: @example +@group 1 2 3 4 5 6 2 3 4 5 6 1 3 4 5 6 1 2 4 5 6 1 2 3 +@end group @end example @noindent il programma produce il seguente output: @example +@group 4 3 2 1 5 4 3 2 6 5 4 3 1 6 5 4 2 1 6 5 3 2 1 6 +@end group @end example @node Visitare vettori multidimensionali @@ -17921,7 +18189,7 @@ permette di verificare se un elemento di un vettore @`e esso stesso un vettore: @example for (i in vettore) @{ - if (isarray(vettore[i]) @{ + if (isarray(vettore[i])) @{ for (j in vettore[i]) @{ print vettore[i][j] @} @@ -17937,15 +18205,19 @@ Per esempio, il seguente codice stampa gli elementi del nostro vettore principale @code{a}: @example +@group for (i in a) @{ for (j in a[i]) @{ if (j == 3) @{ for (k in a[i][j]) print a[i][j][k] +@end group +@group @} else print a[i][j] @} @} +@end group @end example @noindent @@ -18445,9 +18717,11 @@ asort(a) genera i seguenti contenuti di @code{a}: @example +@group a[1] = "cul" a[2] = "de" a[3] = "sac" +@end group @end example La funzione @code{asorti()} si comporta in maniera simile ad @code{asort()}; @@ -18472,8 +18746,9 @@ Se @var{come} @`e una stringa che inizia con @samp{g} o @samp{G} (abbreviazione di ``global''), sostituisce ogni occorrenza di @var{regexp} con la stringa @var{rimpiazzo}. Altrimenti, @var{come} @`e visto come un numero che indica -quale corrispondenza di @var{regexp} va rimpiazzata. Se non si specifica -il nome dell'@var{obiettivo}, si +quale corrispondenza di @var{regexp} va rimpiazzata. Valori numerici +inferiori a uno vengono gestiti come se avessero il valore uno. +Se non si specifica il nome dell'@var{obiettivo}, si opera su @code{$0}. La funzione restituisce come risultato la stringa modificata, e la stringa originale di partenza @emph{non} viene modificata. @@ -18845,8 +19120,8 @@ eventuale spazio bianco a fine stringa viene messo in @code{@var{separatori}[@var{n}]}, dove @var{n} @`e il valore restituito da @code{split()} (cio@`e il numero di elementi in @var{vettore}). -La funzione @code{split()} divide le stringhe in pezzi in modo simile -a quello con cui le righe in input sono divise in campi. Per esempio: +La funzione @code{split()} divide le stringhe in pezzi nello stesso +modo in cui le righe in input sono divise in campi. Per esempio: @example split("cul-de-sac", a, "-", separatori) @@ -18882,6 +19157,9 @@ bianchi. Inoltre, come nel caso della divisione dei record in input, se @var{separacampo} @`e la stringa nulla, ogni singolo carattere nella stringa costituisce un elemento del vettore. @value{COMMONEXT} +Inoltre, se @var{separacampo} @`e una stringa costituita da un unico +carattere, quella stringa fa da separatore, anche se il carattere +in questione @`e un metacarattere usato nella espressioni regolari. Si noti, tuttavia, che @code{RS} non influisce sul comportamento di @code{split()}. @@ -19601,6 +19879,9 @@ buffer di un file o @dfn{pipe} che era stato aperto in lettura o se @var{nome_file} non @`e un file, una @dfn{pipe}, o un coprocesso aperto. in tal caso, @code{fflush()} restituisce ancora @minus{}1. +@c end the table to let the sidebar take up the full width of the page. +@end table + @sidebar Bufferizzazione interattiva e non interattiva @cindex bufferizzazione, interattiva vs.@: non interattiva @@ -19648,13 +19929,14 @@ In questo caso, nessun output viene stampato finch@'e non @`e stato battuto il @dfn{pipe} al comando @command{cat} in un colpo solo. @end sidebar +@table @asis @item @code{system(@var{comando})} @cindexawkfunc{system} @cindex chiamare comandi di shell @cindex interagire con altri programmi Esegue il comando del sistema operativo @var{comando} e quindi ritorna al programma @command{awk}. -Restituisce il codice ritorno di @var{comando}. +Restituisce il codice di ritorno di @var{comando}. Per esempio, inserendo il seguente frammento di codice in un programma @command{awk}: @@ -19712,7 +19994,7 @@ semplicemente limitata a restituire il valore del codice di ritorno diviso per 256 (ossia la met@`a sinistra del numero di 16 bit, spostata a destra). In una situazione normale questo equivale a utilizzare il codice di ritornodi @code{system()}, ma nel caso in cui il programma sia -stato terminato da un segnale, il valore diventa un numero frazionale a +stato terminato da un segnale, il valore diventa un numero frazionale in virgola mobile.@footnote{In uno scambio di messaggi privato il Dr.@: Kernighan mi ha comunicato che questo modo di procedere @`e probabilmente errato.} POSIX stabilisce che la chiamata a @code{system()} dall'interno @@ -19736,6 +20018,9 @@ I valori del codice di ritorno sono descritti nella @end float @end table +A partire dalla versione di agosto 2018, BWK @command{awk} si comporta +come @command{gawk} per il codice di ritorno della chiamata @code{system()}. + @sidebar Controllare la bufferizzazione dell'output con @code{system()} @cindex buffer, scrivere su disco un @cindex bufferizzazione, dell'input/output @@ -20391,7 +20676,7 @@ le operazioni a livello di bit. I parametri facoltativi sono racchiusi tra parentesi quadre ([ ]): @cindex @command{gawk}, operazioni a livello di bit in -@table @code +@table @asis @cindexgawkfunc{and} @cindex AND, operazione sui bit @item @code{and(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)} @@ -20445,7 +20730,7 @@ che illustra l'uso di queste funzioni: @example @group @c file eg/lib/bits2str.awk -# bits2str --- decodifica un byte in una serie di 0/1 leggibili +# bits2str --- decodifica un numero intero in una serie di 0/1 leggibili function bits2str(byte, dati, maschera) @{ @@ -20467,7 +20752,7 @@ function bits2str(byte, dati, maschera) @c this is a hack to make testbits.awk self-contained @ignore @c file eg/prog/testbits.awk -# bits2str --- turn a byte into readable 1's and 0's +# bits2str --- turn an integer into readable ones and zeros function bits2str(bits, data, mask) @{ @@ -20508,8 +20793,8 @@ $ @kbd{gawk -f testbits.awk} @print{} 123 = 01111011 @print{} 0123 = 01010011 @print{} 0x99 = 10011001 -@print{} compl(0x99) = 0x3fffffffffff66 = 001111111111111111111111111111111 -@print{} 11111111111111101100110 +@print{} compl(0x99) = 0x3fffffffffff66 = +@print{} 00111111111111111111111111111111111111111111111101100110 @print{} lshift(0x99, 2) = 0x264 = 0000001001100100 @print{} rshift(0x99, 2) = 0x26 = 00100110 @end example @@ -20546,14 +20831,14 @@ e poi mostra i risultati delle funzioni @sidebar Attenzione. Non @`e tutto oro quel che luccica! In altri linguaggi, le operazioni "bit a bit" sono eseguite su valori interi, -non su valori a virgola mobile. Come regola generale, tali operazioni +non su valori in virgola mobile. Come regola generale, tali operazioni funzionano meglio se eseguite su interi senza segno. @command{gawk} tenta di trattare gli argomenti delle funzioni "bit a bit" come interi senza segno. Per questo motivo, gli argomenti negativi provocano un errore fatale. -In una normale operazione, per tutte queste funzioni, prima il valore a virgola +In una normale operazione, per tutte queste funzioni, prima il valore in virgola mobile a doppia precisione viene convertito nel tipo intero senza segno di C pi@`u ampio, poi viene eseguita l'operazione "bit a bit". Se il risultato non pu@`o essere rappresentato esattamente come un tipo @code{double} di C, @@ -20588,13 +20873,14 @@ $ @kbd{gawk -M 'BEGIN @{ printf "%#x\n", compl(42) @}'} Quando si usa l'opzione @option{-M}, nel dettaglio, @command{gawk} usa gli interi a precisione arbitraria di GNU MP che hanno almeno 64 bit di precisione. Quando non si usa l'opzione @option{-M}, @command{gawk} memorizza i valori -interi come regolari valori a virgola mobile con doppia precisione, che +interi come regolari valori in virgola mobile con doppia precisione, che mantengono solo 53 bit di precisione. Inoltre, la libreria GNU MP tratta -(o almeno sembra che tratti) il bit iniziale come un bit con segno; cos@`i il +(o almeno sembra che tratti) il bit iniziale come un bit con segno; +cos@`{@dotless{i}} il risultato con @option{-M} in questo caso @`e un numero negativo. In breve, usare @command{gawk} per qualsiasi tipo di operazione "bit a bit", -tranne le pi@`u semplici, probabilmente @`e una cattiva idea; caveat emptor! +tranne le pi@`u semplici, probabilmente @`e una cattiva idea; @dfn{caveat emptor}! @end sidebar @@ -20799,10 +21085,12 @@ legge l'intero programma, prima di iniziare ad eseguirlo. La definizione di una funzione chiamata @var{nome} @`e simile a questa: @display +@group @code{function} @var{nome}@code{(}[@var{lista-parametri}]@code{)} @code{@{} @var{corpo-della-funzione} @code{@}} +@end group @end display @cindex nomi di funzione @@ -20989,11 +21277,13 @@ La funzione seguente cancella tutti gli elementi in un vettore l'inizio della lista delle variabili locali): @example +@group function cancella_vettore(a, i) @{ for (i in a) delete a[i] @} +@end group @end example Quando si lavora con vettori, @`e spesso necessario cancellare @@ -21215,10 +21505,12 @@ Inoltre, chiamate ricorsive creano nuovi vettori. Si consideri questo esempio: @example +@group function qualche_funz(p1, a) @{ if (p1++ > 3) return +@end group a[p1] = p1 @@ -21283,12 +21575,14 @@ locali, ci@`o non influisce su nessun'altra variabile. Quindi, se @code{mia_funzione()} fa questo: @example +@group function mia_funzione(stringa) @{ print stringa stringa = "zzz" print stringa @} +@end group @end example @noindent @@ -21466,11 +21760,13 @@ function massimo(vettore, i, max) return max @} +@group # Carica tutti i campi di ogni record in numeri. @{ for (i = 1; i <= NF; i++) numeri[NR, i] = $i @} +@end group END @{ print massimo(numeri) @@ -21606,7 +21902,7 @@ usando la chiamata indiretta di funzioni: @ignore @c file eg/prog/indirectcall.awk # -# Arnold Robbins, arnold@skeeve.com, Public Domain +# Arnold Robbins, arnold@@skeeve.com, Public Domain # January 2009 @c endfile @end ignore @@ -21781,12 +22077,14 @@ di confronto: @example @c file eg/prog/indirectcall.awk +@group # num_min --- confronto numerico per minore di function num_min(sinistra, destra) @{ return ((sinistra + 0) < (destra + 0)) @} +@end group # num_magg_o_ug --- confronto numerico per maggiore o uguale @@ -21839,6 +22137,7 @@ Per finire, le due funzioni di ordinamento chiamano la funzione @example @c file eg/prog/indirectcall.awk +@group # ascendente --- ordina i dati in ordine crescente # e li restituisce sotto forma di stringa @@ -21846,7 +22145,9 @@ function ascendente(primo, ultimo) @{ return ordina(primo, ultimo, "num_min") @} +@end group +@group # discendente --- ordina i dati in ordine decrescente # e li restituisce sotto forma di stringa @@ -21854,6 +22155,7 @@ function discendente(primo, ultimo) @{ return ordina(primo, ultimo, "num_magg_o_ug") @} +@end group @c endfile @end example @@ -22368,7 +22670,7 @@ Se la stringa in input corrisponde all'espressione regolare che descrive i numeri ottali, @code{mystrtonum()} esegue il ciclo per ogni carattere presente nella stringa. Imposta @code{k} all'indice in @code{"1234567"} della cifra ottale corrente. -Il valore di ritorno sar@`a lo stesso numero della cifra, o zero +Il codice di ritorno sar@`a lo stesso numero della cifra, o zero se il carattere non c'@`e, il che succeder@`a per ogni cifra @samp{0}. Questo si pu@`o fare, perch@'e il test di @dfn{regexp} nell'istruzione @code{if} assicura che vengano scelti per @@ -22412,6 +22714,7 @@ il programma. In C, l'uso di @code{assert()} @`e simile a questo: @example +@group #include <assert.h> int myfunc(int a, double b) @@ -22419,6 +22722,7 @@ int myfunc(int a, double b) assert(a <= 5 && b >= 17.1); @dots{} @} +@end group @end example Se l'asserzione @`e falsa, il programma stampa un messaggio simile a questo: @@ -22589,9 +22893,10 @@ function round(x, ival, aval, frazione) @} @c endfile @c don't include test harness in the file that gets installed - +@group # codice per testare, commentato # @{ print $0, round($0) @} +@end group @end example @node Funzione random Cliff @@ -23021,7 +23326,7 @@ rapidamente, e quindi @command{gawk} inserisce in @code{temp} l'intero contenuto del file. (@xref{Record} per informazioni su @code{RT} e @code{RS}.) -Se @code{file} @`e vuoto, il valore di ritorno @`e la stringa vuota. +Se @code{file} @`e vuoto, il codice di ritorno @`e la stringa vuota. Quindi, il codice chiamante pu@`o usare qualcosa simile a questo: @example @@ -23031,7 +23336,7 @@ if (length(contenuto) == 0) @end example La verifica serve a determinare se il file @`e vuoto o no. Una verifica -equivalente potrebbe essere @samp{contenuto == ""}. +equivalente potrebbe essere @samp{@w{contenuto == ""}}. @xref{Esempio di estensione Readfile} per una funzione di estensione anch'essa finalizzata a leggere un intero file in memoria. @@ -23361,8 +23666,10 @@ $ @kbd{gawk -f rewind.awk -f test.awk dati } @print{} data 1 a @print{} data 2 b @print{} data 3 c +@group @print{} data 4 d @print{} data 5 e +@end group @end example @node Controllo di file @@ -23731,7 +24038,7 @@ man mano che si elencano i pezzi di codice che la compongono: @end example La funzione inizia con commenti che elencano e descrivono le variabili globali -utilizzate, spiegano quali sono i valori di ritorno, il loro significato, e +utilizzate, spiegano quali sono i codici di ritorno, il loro significato, e ogni altra variabile che @`e ``esclusiva'' a questa funzione di libreria. Tale documentazione @`e essenziale per qualsiasi programma, e in modo particolare per @@ -24709,8 +25016,10 @@ function getgrent() _gr_init() if (++_gr_contatore in _gr_bycount) return _gr_bycount[_gr_contatore] +@group return "" @} +@end group @c endfile @end example @@ -24751,8 +25060,8 @@ usa queste funzioni. @iftex La @end iftex -@ref{Vettori di vettori} trattava come @command{gawk} -avere a disposizione vettori di vettori. In particolare, qualsiasi elemento di +@ref{Vettori di vettori} trattava di come @command{gawk} +mette a disposizione vettori di vettori. In particolare, qualsiasi elemento di un vettore pu@`o essere uno scalare o un altro vettore. La funzione @code{isarray()} (@pxref{Funzioni per i tipi}) permette di distinguere un vettore @@ -25290,10 +25599,12 @@ preparare la lista dei campi o dei caratteri: if (per_campi == 0 && per_caratteri == 0) per_campi = 1 # default +@group if (lista_campi == "") @{ print "cut: specificare lista per -c o -f" > "/dev/stderr" exit 1 @} +@end group if (per_campi) prepara_lista_campi() @@ -25538,7 +25849,7 @@ da implementare con @command{gawk}; basta usare la variabile predefinita @c file eg/prog/egrep.awk # Opzioni: # -c conta le righe trovate -# -s sileziosa: genera solo il codice di ritorno +# -s silenziosa: genera solo il codice di ritorno # -v inverte test, successo se @dfn{regexp} non presente # -i ignora maiuscolo/minuscolo # -l stampa solo nomi file @@ -25641,8 +25952,8 @@ function a_inizio_file(da_buttare) La funzione @code{endfile()} viene chiamata dopo l'elaborazione di ogni file. Ha influenza sull'output solo quando l'utente desidera un contatore del numero di righe che sono state individuate. @code{non_stampare} @`e vero nel -caso si desideri solo il codice di -ritorno. @code{conta_e_basta} @`e vero se si desiderano solo i contatori +caso si desideri solo il codice di ritorno. +@code{conta_e_basta} @`e vero se si desiderano solo i contatori delle righe trovate. @command{egrep} quindi stampa i contatori solo se sia la stampa che il conteggio delle righe sono stati abilitati. @@ -25662,8 +25973,10 @@ function endfile(file) print contatore_file @} +@group totale += contatore_file @} +@end group @c endfile @end example @@ -25837,11 +26150,15 @@ BEGIN @{ pw = getpwuid(uid) stampa_primo_campo(pw) +@group if (euid != uid) @{ printf(" euid=%d", euid) pw = getpwuid(euid) +@end group +@group stampa_primo_campo(pw) @} +@end group printf(" gid=%d", gid) pw = getgrgid(gid) @@ -25974,14 +26291,17 @@ BEGIN @{ # testa argv nel caso che si legga da stdin invece che da file if (i in ARGV) i++ # salta nome file-dati +@group if (i in ARGV) @{ outfile = ARGV[i] ARGV[i] = "" @} - +@end group +@group s1 = s2 = "a" out = (outfile s1 s2) @} +@end group @c endfile @end example @@ -26146,11 +26466,15 @@ indicato nella riga di comando, e poi sullo standard output: @`E anche possibile scrivere il ciclo cos@`{@dotless{i}}: @example +@group for (i in copia) if (append) print >> copia[i] +@end group +@group else print > copia[i] +@end group @end example @noindent @@ -26305,10 +26629,12 @@ BEGIN @{ sintassi() @} +@group if (ARGV[Optind] ~ /^\+[[:digit:]]+$/) @{ conta_caratteri = substr(ARGV[Optind], 2) + 0 Optind++ @} +@end group for (i = 1; i < Optind; i++) ARGV[i] = "" @@ -26345,11 +26671,13 @@ occorre saltare dei caratteri, si usa @code{substr()} per eliminare i primi @example @c file eg/prog/uniq.awk +@group function se_sono_uguali( n, m, campi_ultima, campi_corrente,\ vettore_ultima, vettore_corrente) @{ if (contatore_file == 0 && conta_caratteri == 0) return (ultima == $0) +@end group if (contatore_file > 0) @{ n = split(ultima, vettore_ultima) @@ -26364,9 +26692,11 @@ vettore_ultima, vettore_corrente) campi_ultima = substr(campi_ultima, conta_caratteri + 1) campi_corrente = substr(campi_corrente, conta_caratteri + 1) @} +@group return (campi_ultima == campi_corrente) @} +@end group @c endfile @end example @@ -26428,11 +26758,13 @@ NR == 1 @{ END @{ if (conta_record) printf("%4d %s\n", contatore, ultima) > file_output +@group else if ((solo_ripetute && contatore > 1) || (solo_non_ripetute && contatore == 1)) print ultima > file_output close(file_output) @} +@end group @c endfile @end example @@ -27272,10 +27604,12 @@ A prima vista, un programma come questo sembrerebbe essere sufficiente: freq[$i]++ @} +@group END @{ for (word in freq) printf "%s\t%d\n", word, freq[word] @} +@end group @end example Il programma si affida al meccanismo con cui @command{awk} divide i campi per @@ -27662,7 +27996,7 @@ La riga @`e poi stampata nel file di output: @} if ($3 != file_corrente) @{ if (file_corrente != "") - close(file_corrente) + lista_file[file_corrente] = 1 # memorizza per chiudere dopo file_corrente = $3 @} @@ -27689,9 +28023,11 @@ La riga @`e poi stampata nel file di output: i++ @} @} +@group print join(a, 1, n, SUBSEP) > file_corrente @} @} +@end group @c endfile @end example @@ -27699,14 +28035,35 @@ La riga @`e poi stampata nel file di output: L'output fatto usando @samp{>} apre il file solo la prima volta; il file resta poi aperto, e ogni scrittura successiva @`e aggiunta in fondo al file. (@pxref{Ridirezione}). -Ci@`o rende possibile mischiare testo del programm e commenti esplicativi +Ci@`o rende agevole mischiare testo del programma e commenti esplicativi (come @`e stato fatto qui) nello stesso file sorgente, senza nessun problema. Il file viene chiuso solo quando viene trovato un nuovo nome di @value{DF} oppure alla fine del file in input. +Quando si incontra un nuovo @value{FN}, invece di chiudere il file, +il programma memorizza il nome del file corrente in @code{lista_file}. +Ci@`o rende possibile mischiare il codice per pi@`u di un file nel file +sorgente Texinfo in input. (Precedenti versioni di questo programma +chiudevano @emph{davvero} il file. Ma, a causa della ridirezione +@samp{>}, un file le cui parti non erano tutte una di seguito all'altra +finiva per contenere errori.) +Una regola @code{END} effettua la chiusura di tutti i file aperti, quando +l'elaborazione @`e stata completata: + +@example +@c file eg/prog/extract.awk +@group +END @{ + close(file_corrente) # chiudi l'ultimo file + for (f in lista_file) # chiudi tutti gli altri + close(f) +@} +@end group +@c endfile +@end example + Per finire, la funzione @code{@w{fine_file_inattesa()}} stampa un -appropriato messaggio di errore ed esce. -La regola @code{END} gestisce la pulizia finale, chiudendo il file aperto: +appropriato messaggio di errore ed esce: @example @c file eg/prog/extract.awk @@ -27718,11 +28075,6 @@ function fine_file_inattesa() exit 1 @} @end group - -END @{ - if (file_corrente) - close(file_corrente) -@} @c endfile @end example @@ -27784,10 +28136,12 @@ function sintassi() exit 1 @} +@group BEGIN @{ # valida argomenti if (ARGC < 3) sintassi() +@end group RS = ARGV[1] ORS = ARGV[2] @@ -28216,13 +28570,11 @@ di zero, il programma @`e terminato: continue @} cammino = percorso($2) -@group if (cammino == "") @{ printf("igawk: %s:%d: non riesco a trovare %s\n", input[indice_pila], FNR, $2) > "/dev/stderr" continue @} -@end group if (! (cammino in gia_fatto)) @{ gia_fatto[cammino] = input[indice_pila] input[++indice_pila] = cammino # aggiungilo alla pila @@ -28493,10 +28845,12 @@ notice and this notice are preserved. Ecco il programma: @example +@group awk 'BEGIN@{O="~"~"~";o="=="=="==";o+=+o;x=O""O;while(X++<=x+o+o)c=c"%c"; printf c,(x-O)*(x-O),x*(x-o)-o,x*(x-O)+x-O-o,+x*(x-O)-x+o,X*(o*o+O)+x-O, X*(X-x)-o*o,(x+X)*o*o+o,x*(X-x)-O-O,x-O+(O+o+X+x)*(o+O),X*X-X*(x-O)-x+O, O+X*(o*(o+O)+O),+x+O+X*o,x*(x-o),(o+X+x)*o*o-(x-O-O),O+(X-x)*(X+O),x-O@}' +@end group @end example @c genera l'email del tizio: @c dave_br@gmx.com @@ -29022,7 +29376,7 @@ sono i corrispondenti valori dei due elementi che si stanno confrontando. @code{v1} oppure @code{v2}, o entrambi, possono essere vettori se il vettore che si sta visitando contiene sottovettori come valori. (@xref{Vettori di vettori} per maggiori informazioni sui sottovettori.) -I tre possibili valori di ritorno sono interpretati nel seguente modo: +I tre possibili codici di ritorno sono interpretati nel seguente modo: @table @code @item confronta(i1, v1, i2, v2) < 0 @@ -29042,11 +29396,13 @@ La prima funzione di confronto pu@`o essere usata per scorrere un vettore secondo l'ordine numerico degli indici: @example +@group function cfr_ind_num(i1, v1, i2, v2) @{ # confronto di indici numerici, ordine crescente return (i1 - i2) @} +@end group @end example La seconda funzione scorre un vettore secondo l'ordine delle stringhe @@ -29155,10 +29511,13 @@ function per_campo(i1, v1, i2, v2) a[NR][i] = $i @} +@group END @{ PROCINFO["sorted_in"] = "per_campo" +@end group if (POS < 1 || POS > NF) POS = 1 + for (i in a) @{ for (j = 1; j <= NF; j++) printf("%s%c", a[i][j], j < NF ? ":" : "") @@ -29215,6 +29574,7 @@ function per_numero(i1, v1, i2, v2) return (v1 != v2) ? (v2 - v1) : (i2 - i1) @} +@group function per_stringa(i1, v1, i2, v2) @{ # confronto di valori di stringa (e indici), ordine decrescente @@ -29222,6 +29582,7 @@ function per_stringa(i1, v1, i2, v2) v2 = v2 i2 return (v1 > v2) ? -1 : (v1 != v2) @} +@end group @end example @c Avoid using the term ``stable'' when describing the unpredictable behavior @@ -29288,7 +29649,7 @@ for (i = 1; i <= n; i++) Dopo la chiamata ad @code{asort()}, il vettore @code{dati} @`e indicizzato da 1 a @var{n}, il numero totale di elementi in @code{dati}. -(Questo conteggio @`e il valore di ritorno di @code{asort()}). +(Questo conteggio @`e il codice di ritorno di @code{asort()}). @code{dati[1]} @value{LEQ} @code{dati[2]} @value{LEQ} @code{dati[3]}, e cos@`{@dotless{i}} via. Il confronto di default @`e basato sul tipo di elementi (@pxref{Tipi di variabile e confronti}). @@ -29387,11 +29748,13 @@ trasforma gli elementi da confrontare in lettere minuscole, in modo da avere confronti che non dipendono da maiuscolo/minuscolo. @example +@group # confronta_in_minuscolo --- confronta stringhe ignorando maiuscolo/minuscolo function confronta_in_minuscolo(i1, v1, i2, v2, l, r) @{ l = tolower(v1) +@end group r = tolower(v2) if (l < r) @@ -29678,6 +30041,55 @@ programmazione attenta, insieme alla conoscenza del comportamento del coprocesso. @end quotation +@c From email send January 4, 2018. +L'esempio seguente, preparato da Andrew Schorr, dimostra come +l'utilizzo delle @dfn{pty} pu@`o servire a evitare situazioni +di stallo connesse con i buffer + +Si supponga che @command{gawk} non sia in grado di sommare dei numeri. +Si potrebbe usare un coprocesso per farlo. Ecco un programma fin troppo +semplice, che pu@`o svolgere tale funzione: + +@example +$ @kbd{cat add.c} +#include <stdio.h> + +int +main(void) +@{ + int x, y; + while (scanf("%d %d", & x, & y) == 2) + printf("%d\n", x + y); + return 0; +@} +$ @kbd{cc -O add.c -o add} @ii{Compilazione del programma} +@end example + +Si potrebbe poi scrivere un programma @command{gawk} fin troppo semplice, +per sommare dei numeri passandoli al coprocesso: + +@example +$ @kbd{echo 1 2 |} +> @kbd{gawk -v cmd=./add '@{ print |& cmd; cmd |& getline x; print x @}'} +@end example + +E il programma andrebbe in stallo, poich@'e, @file{add.c} non chiama a sua +volta @samp{setlinebuf(stdout)}. Il programma @command{add} si blocca. + +Ora, si provi invece con: + +@example +$ @kbd{echo 1 2 |} +> @kbd{gawk -v cmd=add 'BEGIN @{ PROCINFO[cmd, "pty"] = 1 @}} +> @kbd{ @{ print |& cmd; cmd |& getline x; print x @}'} +@print{} 3 +@end example + +Usando una @dfn{pty}, @command{gawk} fa s@`{@dotless{i}} che la libreria di I/O +determini di avere a che fare con una sessione interattiva, e quindi +utilizzi per default una riga alla volta come buffer. +E ora, magicamente, funziona! + @node Reti TCP/IP @section Usare @command{gawk} per la programmazione di rete @cindex funzionalit@`a avanzate, programmazione di rete @@ -29794,7 +30206,7 @@ TCP del sistema locale. Stampa poi il risultato e chiude la connessione. Poich@'e questo tema @`e molto ampio, l'uso di @command{gawk} per -la programmazione TCP/IP viene documentato separatamente. +la programmazione TCP/IP viene documentata separatamente. @ifinfo Si veda @inforef{Top, , General Introduction, gawkinet, @value{GAWKINETTITLE}}, @@ -30010,6 +30422,8 @@ struttura del programma e dalle regole di precedenza. Per esempio, @samp{(3 + 5) * 4} significa sommare tre e cinque, quindi moltiplicare il totale per quattro. Di contro, @samp{3 + 5 * 4} non ha parentesi, e significa @samp{3 + (5 * 4)}. +Tuttavia, le parentesi inserite esplicitamente nel programma sorgente +sono conservate come sono state scritte. @ignore @item @@ -30048,12 +30462,14 @@ appaiono come: @example /pippo/ @{ - print $0 + print @} @end example @noindent che @`e corretto, ma probabilmente inatteso. +(Se un programma usa sia @samp{print $0} che un semplice +@samp{print}, tale differenza @`e mantenuta.) @cindex profilare programmi @command{awk}, dinamicamente @cindex @command{gawk}, programma, profilazione dinamica @@ -30135,16 +30551,15 @@ Una volta, l'opzione @option{--pretty-print} eseguiva anche il programma. Ora non pi@`u. @end quotation -C'@`e una differenza significativa tra l'output creato durante la profilazione, e -quello creato durante la stampa elegante. L'output della stampa elegante +C'@`e una differenza significativa tra l'output creato durante la profilazione, +e quello creato durante la stampa elegante. L'output della stampa elegante preserva i commenti originali che erano nel programma, anche se la loro posizione pu@`o non corrispondere esattamente alle posizioni originali che -avevano nel codice sorgente.@footnote{@command{gawk} fa del suo meglio +avevano nel codice sorgente. Tuttavia, nessun commento dovrebbe andare +perso. Inoltre, @command{gawk} fa del suo meglio per mantenere la distinzione tra commenti posti dopo delle istruzioni e -commenti su righe a s@'e stanti. Per limiti insiti nell'implementazione, -non sempre questo pu@`o avvenire in maniera corretta, in particolare nel -caso di istruzioni @code{switch}. I manutentori di @command{gawk} -sperano di poter migliorare la situazione in una futura versione.} +commenti su righe a s@'e stanti. Tuttavia, non sempre questo pu@`o avvenire +in maniera perfetta. Comunque, per una precisa scelta progettuale, l'output della profilazione @emph{omette} i commenti del programma originale. Questo permette di @@ -30863,9 +31278,11 @@ con altri contenenti degli specificatori posizionali in una stessa stringa di formato: @example +@group $ @kbd{gawk 'BEGIN @{ printf "%d %3$s\n", 1, 2, "ciao" @}'} @error{} gawk: riga com.:1: fatale: `count$' va usato per tutti @error{} i formati o per nessuno +@end group @end example @quotation NOTA @@ -31287,7 +31704,7 @@ attiva. Tale pila (@dfn{stack}) @`e chiamata @dfn{call stack} (pila delle chiam Per ciascuna funzione della pila delle chiamate (@dfn{call stack}), il sistema mantiene un'area di dati che contiene i parametri della funzione, le variabili -locali e i valori di ritorno, e anche ogni altra informazione ``contabile'' +locali e i codici di ritorno, e anche ogni altra informazione ``contabile'' necessaria per gestire la pila delle chiamate. Quest'area di dati @`e chiamata @dfn{stack frame}. @@ -31535,8 +31952,10 @@ ulteriormente, iniziamo a ``scorrere una ad una'' le righe di [successivo]): @example +@group gawk> @kbd{n} @print{} 66 if (contatore_file > 0) @{ +@end group @end example Questo ci dice che @command{gawk} ora @`e pronto per eseguire la riga 66, che @@ -31938,7 +32357,7 @@ Esegue una o @var{contatore} istruzioni, comprese le chiamate di funzione. @cindex @code{return}, comando del debugger @item @code{return} [@var{valore}] Cancella l'esecuzione di una chiamata di funzione. Se @var{valore} (una -stringa o un numero) viene specificato, @`e usato come valore di ritorno della +stringa o un numero) viene specificato, @`e usato come codice di ritorno della funzione. Se usato in un frame diverso da quello pi@`u interno (la funzione correntemente in esecuzione; cio@`e, il frame numero 0), ignora tutti i frame pi@`u interni di quello selezionato, e il chiamante del frame selezionato @@ -32364,10 +32783,12 @@ Davide Brini (@pxref{Programma signature}): @c FIXME: This will need updating if num-handler branch is ever merged in. @smallexample +@group gawk> @kbd{dump} @print{} # BEGIN @print{} @print{} [ 1:0xfcd340] Op_rule : [in_rule = BEGIN] [source_file = brini.awk] +@end group @print{} [ 1:0xfcc240] Op_push_i : "~" [MALLOC|STRING|STRCUR] @print{} [ 1:0xfcc2a0] Op_push_i : "~" [MALLOC|STRING|STRCUR] @print{} [ 1:0xfcc280] Op_match : @@ -32400,18 +32821,18 @@ gawk> @kbd{dump} @print{} [ :0xfcc660] Op_no_op : @print{} [ 1:0xfcc520] Op_assign_concat : c @print{} [ :0xfcc620] Op_jmp : [target_jmp = 0xfcc440] -@print{} @dots{} -@print{} @print{} [ 2:0xfcc5a0] Op_K_printf : [expr_count = 17] [redir_type = ""] @print{} [ :0xfcc140] Op_no_op : @print{} [ :0xfcc1c0] Op_atexit : @print{} [ :0xfcc640] Op_stop : @print{} [ :0xfcc180] Op_no_op : @print{} [ :0xfcd150] Op_after_beginfile : +@group @print{} [ :0xfcc160] Op_no_op : @print{} [ :0xfcc1a0] Op_after_endfile : gawk> +@end group @end smallexample @cindex comando del debugger, @code{exit} @@ -32805,55 +33226,84 @@ mentre i valori senza segno sono sempre maggiori o uguali a zero. Nei sistemi informatici, il calcolo con valori interi @`e esatto, ma il possibile campo di variazione dei valori @`e limitato. L'elaborazione con numeri interi @`e -pi@`u veloce di quella con numeri a virgola mobile. +pi@`u veloce di quella con numeri in virgola mobile. -@item La matematica coi numeri a virgola mobile -I numeri a virgola mobile rappresentano quelli che a scuola sono chiamati +@cindex virgola mobile, numeri in +@cindex numeri in virgola mobile +@item La matematica coi numeri in virgola mobile +I numeri in virgola mobile rappresentano quelli che a scuola sono chiamati numeri ``reali'' (cio@`e, quelli che hanno una parte frazionaria, come -3.1415927). Il vantaggio dei numeri a virgola mobile @`e che essi possono +3.1415927). Il vantaggio dei numeri in virgola mobile @`e che essi possono rappresentare uno spettro di valori molto pi@`u ampio di quello rappresentato dai numeri interi. Lo svantaggio @`e che ci sono numeri che essi non possono rappresentare in modo esatto. -I computer moderni possono eseguire calcoli su valori a virgola mobile +I computer moderni possono eseguire calcoli su valori in virgola mobile nell'hardware dell'elaboratore, entro un intervallo di valori limitato. -Ci sono inoltre librerie di programmi che consentono calcoli, usando numeri a +Ci sono inoltre librerie di programmi che consentono calcoli, usando numeri in virgola mobile, di precisione arbitraria. -POSIX @command{awk} usa numeri a virgola mobile a @dfn{doppia precisione}, -che possono gestire pi@`u cifre rispetto ai numeri a virgola mobile a +@cindex virgola mobile, numeri in@comma{} precisione singola +@cindex virgola mobile, numeri in@comma{} precisione doppia +@cindex virgola mobile, numeri in@comma{} precisione arbitraria +@cindex precisione singola +@cindex precisione doppia +@cindex precisione arbitraria +@cindex singola, precisione +@cindex doppia, precisione +@cindex arbitraria, precisione +POSIX @command{awk} usa numeri in virgola mobile a @dfn{doppia precisione}, +che possono gestire pi@`u cifre rispetto ai numeri in virgola mobile a @dfn{singola precisione}. @command{gawk} ha inoltre funzionalit@`a, descritte in dettaglio pi@`u sotto, che lo mettono in grado di eseguire -calcoli con i numeri a virgola mobile con precisione arbitraria. +calcoli con i numeri in virgola mobile con precisione arbitraria. @end table -I calcolatori operano con valori interi e a virgola mobile su diversi +I calcolatori operano con valori interi e in virgola mobile su diversi intervalli. I valori interi normalmente hanno una dimensione di 32 bit o 64 bit. -I valori a virgola mobile a singola precisione occupano 32 bit, mentre i -valori a virgola mobile a doppia precisione occupano 64 bit. I valori a -virgola mobile sono sempre con segno. Il possibile campo di variazione dei -valori @`e mostrato in @ref{table-numeric-ranges}. +I valori in virgola mobile a singola precisione occupano 32 bit, mentre i +valori in virgola mobile a doppia precisione occupano 64 bit. +(Esistono anche numeri in virgola mobile a precisione quadrupla. Occupano +128 bit, ma non sono disponibili in @command{awk}.) +I valori in virgola mobile sono sempre con segno. I possibili campi di +variazione dei valori sono mostrati in @ref{table-numeric-ranges} e in +@ref{table-floating-point-ranges}. @float Tabella,table-numeric-ranges -@caption{Intervalli dei valori per diverse rappresentazioni numeriche} +@caption{Intervallo di valori per rappresentazioni di numeri interi} @multitable @columnfractions .34 .33 .33 -@headitem Rappresentazione numerica @tab Valore minimo @tab Valore massimo +@headitem Rappresentazione @tab Valore minimo @tab Valore massimo @item Interi con segno a 32-bit @tab @minus{}2.147.483.648 @tab 2.147.483.647 @item Interi senza segno a 32-bit @tab 0 @tab 4.294.967.295 @item Interi con segno a 64-bit @tab @minus{}9.223.372.036.854.775.808 @tab 9.223.372.036.854.775.807 @item Interi senza segno a 64-bit @tab 0 @tab 18.446.744.073.709.551.615 +@end multitable +@end float + +@float Tabella,table-floating-point-ranges +@caption{Intervallo di valori per rappresentazioni di numeri in virgola mobile} +@multitable @columnfractions .34 .22 .22 .22 @iftex -@item Virgola mobile, singola precisione (circa) @tab @math{1,175494^{-38}} @tab @math{3,402823^{38}} -@item Virgola mobile, doppia precisione (circa) @tab @math{2,225074^{-308}} @tab @math{1,797693^{308}} +@headitem Rappresentazione @tab @w{Valore positivo} @w{minimo} @w{diverso da zero} @tab @w{Valore finito} @w{minimo} @tab @w{Valore finito} @w{massimo} +@end iftex +@ifnottex +@headitem Rappresentazione @tab Valore positivo minimo diverso da zero @tab Valore finito minimo @tab Valore finito massimo +@end ifnottex +@iftex +@item @w{Virgola mobile, singola precis.} @tab @math{1,175494 @cdot 10^{-38}} @tab @math{-3,402823 @cdot 10^{38}} @tab @math{3,402823 @cdot 10^{38}} +@item @w{Virgola mobile, doppia precis.} @tab @math{2,225074 @cdot 10^{-308}} @tab @math{-1,797693 @cdot 10^{308}} @tab @math{1,797693 @cdot 10^{308}} +@item @w{Virgola mobile, quadrupla prec.} @tab @math{3,362103 @cdot 10^{-4932}} @tab @math{-1,189731 @cdot 10^{4932}} @tab @math{1,189731 @cdot 10^{4932}} @end iftex @ifinfo -@item Virgola mobile, singola precisione (circa) @tab 1,175494e-38 @tab 3,402823e38 -@item Virgola mobile, doppia precisione (circa) @tab 2,225074e-308 @tab 1,797693e308 +@item Virgola mobile, singola precis. @tab 1,175494e-38 @tab -3,402823e38 @tab 3,402823e38 +@item Virgola mobile, doppia precis. @tab 2,225074e-308 @tab -1,797693e308 @tab 1,797693e308 +@item Virgola mobile, quadrupla prec. @tab 3,362103e-4932 @tab -1,189731e4932 @tab 1,189731e4932 @end ifinfo @ifnottex @ifnotinfo -@item Virgola mobile, singola precisione (circa) @tab 1,175494@sup{-38} @tab 3,402823@sup{38} -@item Virgola mobile, singola precisione (circa) @tab 2,225074@sup{-308} @tab 1,797693@sup{308} +@item Virgola mobile, singola precis. @tab 1,175494@sup{-38} @tab -3,402823@sup{38} @tab 3,402823*10@sup{38} +@item Virgola mobile, singola precis. @tab 2,225074@sup{-308} @tab -1,797693@sup{308} @tab 1,797693*10@sup{308} +@item Virgola mobile, quadrupla prec. @tab 3,362103@sup{-4932} @tab -1,189731@sup{4932} @tab 1,189731@sup{4932} @end ifnotinfo @end ifnottex @end multitable @@ -32868,7 +33318,7 @@ per la lettura di questo documento: @table @dfn @item Accuratezza -L'accuratezza del calcolo sui numeri a virgola mobile indica di quanto si +L'accuratezza del calcolo sui numeri in virgola mobile indica di quanto si avvicina il calcolo al valore reale (calcolato con carta e penna). @item Errore @@ -32878,14 +33328,14 @@ possibile. @item Esponente L'ordine di grandezza di un valore; -alcuni bit in un valore a virgola mobile contengono l'esponente. +alcuni bit in un valore in virgola mobile contengono l'esponente. @item Inf Un valore speciale che rappresenta l'infinito. Le operazioni tra un qualsiasi numero e l'infinito danno infinito. @item Mantissa -Un valore a virgola mobile @`e formato dalla mantissa moltiplicata per 10 +Un valore in virgola mobile @`e formato dalla mantissa moltiplicata per 10 alla potenza dell'esponente. Per esempio, in @code{1,2345e67}, la mantissa @`e @code{1,2345}. @@ -32920,7 +33370,7 @@ generato il numero), ma non @`e memorizzato fisicamente. Questo fornisce un bit di precisione in pi@`u. @item Precisione -Il numero di bit usati per rappresentare un numero a virgola mobile. +Il numero di bit usati per rappresentare un numero in virgola mobile. Pi@`u sono i bit, e maggiore @`e l'intervallo di cifre che si possono rappresentare. Le precisioni binaria e decimale sono legate in modo approssimativo, secondo @@ -33069,10 +33519,10 @@ ottenere ulteriori informazioni, e non basarsi solo su quanto qui detto. @node Inesattezza nei calcoli @subsection La matematica in virgola mobile non @`e esatta -Le rappresentazioni e i calcoli con numeri a virgola mobile binari sono +Le rappresentazioni e i calcoli con numeri in virgola mobile binari sono inesatti. Semplici valori come 0,1 non possono essere rappresentati in modo -preciso usando numeri a virgola mobile binari, e la limitata precisione dei -numeri a virgola mobile significa che piccoli cambiamenti nell'ordine delle +preciso usando numeri in virgola mobile binari, e la limitata precisione dei +numeri in virgola mobile significa che piccoli cambiamenti nell'ordine delle operazioni o la precisione di memorizzazione di operazioni intermedie pu@`o cambiare il risultato. Per rendere la situazione pi@`u difficile, nel calcolo in virgola @@ -33102,7 +33552,7 @@ Diversamente dal numero in @code{y}, il numero memorizzato in @code{x} @`e rappresentabile esattamente nel formato binario, perch@'e pu@`o essere scritto come somma finita di una o pi@`u frazioni i cui denominatori sono tutti multipli di due. -Quando @command{gawk} legge un numero a virgola mobile dal sorgente di un +Quando @command{gawk} legge un numero in virgola mobile dal sorgente di un programma, arrotonda automaticamente quel numero alla precisione, quale che sia, supportata dal computer in uso. Se si tenta di stampare il contenuto numerico di una variabile usando una stringa di formato in uscita di @@ -33125,7 +33575,7 @@ nell'esempio precedente, d@`a luogo a un output identico all'input. Poich@'e la rappresentazione interna del computer pu@`o discostarsi, sia pur di poco, dal valore -esatto, confrontare dei valori a virgola mobile per vedere se sono esattamente +esatto, confrontare dei valori in virgola mobile per vedere se sono esattamente uguali @`e generalmente una pessima idea. Questo @`e un esempio in cui tale confronto non funziona come dovrebbe: @@ -33134,30 +33584,34 @@ $ @kbd{gawk 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'} @print{} 0 @end example -Il metodo generalmente seguito per confrontare valori a virgola mobile +Il metodo generalmente seguito per confrontare valori in virgola mobile consiste nel controllare se la differenza tra loro @`e minore di un certo valore (chiamato @dfn{delta}, o @dfn{tolleranza}). Quel che si deve decidere @`e qual @`e il valore minimo di delta adeguato. Il codice per far ci@`o @`e qualcosa del genere: @example +@group delta = 0.00001 # per esempio -differenza = abs(a) - abs(b) # sottrazione dei due valori +differenza = abs(a - b) # sottrazione dei due valori if (differenza < delta) # va bene else # non va bene +@end group @end example @noindent -(Si presuppone che sia stata definita in qualche parte del programma una -semplice funzione che restituisce il valore assoluto di un numero, -chiamata @code{abs()}.) +(Si presuppone che sia stata definita in qualche altra parte del programma +una semplice funzione di nome @code{abs()}.) Se si scrive una funzione +per confrontare dei valori con un valore dato @samp{delta}, si dovrebbe +utilizzare la notazione @samp{differenza < abs(delta)} nel caso che +a @samp{delta} venga assegnato un valore negativo. @node Gli errori si sommano @subsubsection Gli errori diventano sempre maggiori -La perdita di accuratezza in un singolo calcolo con numeri a virgola mobile +La perdita di accuratezza in un singolo calcolo con numeri in virgola mobile generalmente non dovrebbe destare preoccupazione. Tuttavia, se si calcola un valore che @`e una sequenza di operazioni in virgola mobile, l'errore si pu@`o accumulare e influire sensibilmente sul risultato del calcolo stesso. @@ -33372,6 +33826,8 @@ $ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", 1/10) @}'} @node Impostare modo di arrotondare @subsection Impostare la modalit@`a di arrotondamento +@cindex @code{ROUNDMODE}, variable +@cindex variabile @code{ROUNDMODE} La variabile @code{ROUNDMODE} permette di controllare a livello di programma la modalit@`a di arrotondamento. La corrispondenza tra @code{ROUNDMODE} e le modalit@`a di arrotondamento IEEE @@ -33385,14 +33841,15 @@ La corrispondenza tra @code{ROUNDMODE} e le modalit@`a di arrotondamento IEEE @item Arrotonda verso infinito @tab @code{roundTowardPositive} @tab @code{"U"} o @code{"u"} @item Arrotonda verso meno infinito @tab @code{roundTowardNegative} @tab @code{"D"} o @code{"d"} @item Arrotonda verso zero (troncamento) @tab @code{roundTowardZero} @tab @code{"Z"} o @code{"z"} -@item Arrotonda al pi@`u vicino, o per eccesso @tab @code{roundTiesToAway} @tab @code{"A"} o @code{"a"} +@item Arrotonda lontano da zero (per eccesso) @tab @tab @code{"A"} o @code{"a"} @end multitable @end float @code{ROUNDMODE} ha @code{"N"} come valore di default, ovvero si usa la modalit@`a di arrotondamento IEEE 754 @code{roundTiesToEven}. In @ref{table-gawk-rounding-modes}, il valore @code{"A"} seleziona -@code{roundTiesToAway}. Questo @`e applicabile solo se la versione in uso +l'arrotondamento lontano da zero (per eccesso). +Questo @`e applicabile solo se la versione in uso della libreria MPFR lo supporta; altrimenti, l'impostazione di @code{ROUNDMODE} ad @code{"A"} non ha alcun effetto. @@ -33409,7 +33866,7 @@ In questo caso, il numero @`e arrotondato alla cifra @emph{pari} pi@`u prossima. Cos@`{@dotless{i}} arrotondando 0.125 alle due cifre si arrotonda per difetto a 0.12, ma arrotondando 0.6875 alle tre cifre si arrotonda per eccesso a 0.688. Probabilmente ci si @`e gi@`a imbattuti in questa modalit@`a di arrotondamento -usando @code{printf} per formattare numeri a virgola mobile. +usando @code{printf} per formattare numeri in virgola mobile. Per esempio: @example @@ -33447,6 +33904,32 @@ valori equidistanti in eccesso e in difetto si distribuiscono pi@`u o meno uniformemente, con la possibile conseguenza che errori di arrotondamento ripetuti tendono ad annullarsi a vicenda. Questa @`e la modalit@`a di arrotondamento di default per funzioni e operatori di calcolo secondo IEEE 754. +@c January 2018. Thanks to nethox@gmail.com for the example. +@sidebar Modalit@`a di arrotondamento e conversioni +@`E importante comprendere che, insieme a @code{CONVFMT} e +@code{OFMT}, la modalit@`a di arrotondamento ha effetto anche sul +modo con cui i numeri sono convertiti in stringhe di caratteri. +Per esempio,si consideri il seguente programma: + +@example +BEGIN @{ + pi = 3.1416 + OFMT = "%.f" # Stampa il valore come numero intero + print pi # ROUNDMODE = "N" per default. + ROUNDMODE = "U" # Ora si cambia ROUNDMODE + print pi +@} +@end example + +@noindent +L'esecuzione di questo programma produce il seguente output: + +@example +$ @kbd{gawk -M -f roundmode.awk} +@print{} 3 +@print{} 4 +@end example +@end sidebar Le altre modalit@`a di arrotondamento sono usate raramente. Gli arrotondamenti verso l'infinito (@code{roundTowardPositive}) e verso il meno infinito @@ -33454,10 +33937,9 @@ verso l'infinito (@code{roundTowardPositive}) e verso il meno infinito intervalli, dove si adotta questa modalit@`a di arrotondamento per calcolare i limiti superiore e inferiore per l'intervallo di valori in uscita. La modalit@`a -@code{roundTowardZero} pu@`o essere usata per convertire numeri a virgola mobile -in numeri interi. La modalit@`a di arrotondamento @code{roundTiesToAway} -arrotonda il risultato al numero pi@`u vicino, e in caso di equidistanza -arrotonda per eccesso. +@code{roundTowardZero} pu@`o essere usata per convertire numeri in virgola mobile +in numeri interi. Quando si arrotonda lontano da zero (per eccesso), viene +scelto il numero pi@`u vicino di grandezza maggiore o uguale al valore. Qualche esperto di analisi numerica dir@`a che la scelta dello stile di arrotondamento ha un grandissimo impatto sul risultato finale, e consiglier@`a @@ -33494,7 +33976,7 @@ disponibile. Per esempio, il seguente programma calcola 5@sup{4@sup{3@sup{2}}}, @end ifnotinfo @end ifnottex -il cui risultato @`e oltre i limiti degli ordinari valori a virgola mobile a +il cui risultato @`e oltre i limiti degli ordinari valori in virgola mobile a doppia precisione dei processori: @example @@ -33507,7 +33989,7 @@ $ @kbd{gawk -M 'BEGIN @{} @print{} 62060698786608744707 ... 92256259918212890625 @end example -Se invece si dovesse calcolare lo stesso valore usando valori a virgola mobile +Se invece si dovesse calcolare lo stesso valore usando valori in virgola mobile con precisione arbitraria, la precisione necessaria per il risultato corretto (usando la formula @@ -33528,8 +34010,8 @@ would be @end docbook o 608693. -Il risultato di un'operazione aritmetica tra un intero e un valore a virgola -mobile @`e un valore a virgola mobile con precisione uguale alla precisione di +Il risultato di un'operazione aritmetica tra un intero e un valore in virgola +mobile @`e un valore in virgola mobile con precisione uguale alla precisione di lavoro. Il seguente programma calcola l'ottavo termine nella successione di Sylvester@footnote{Weisstein, Eric W. @cite{Sylvester's Sequence}. From MathWorld---A Wolfram Web Resource @@ -33555,7 +34037,7 @@ esattamente il risultato in virgola mobile. Si pu@`o o aumentare la precisione gli interi per ottenere l'output corretto. A volte @command{gawk} deve convertire implicitamente un intero con precisione -arbitraria in un valore a virgola mobile con precisione arbitraria. +arbitraria in un valore in virgola mobile con precisione arbitraria. Ci@`o si rende necessario principalmente perch@'e la libreria MPFR non sempre prevede l'interfaccia necessaria per elaborare interi a precisione arbitraria o numeri di tipo @@ -33563,7 +34045,7 @@ eterogeneo come richiesto da un'operazione o funzione. In tal caso, la precisione viene impostata al minimo valore necessario per una conversione esatta, e non viene usata la precisione di lavoro. Se questo non @`e quello di cui si ha bisogno o che si vuole, si pu@`o ricorrere a un -sotterfugio e convertire preventivamente l'intero in un valore a virgola +sotterfugio e convertire preventivamente l'intero in un valore in virgola mobile, come qui di seguito: @example @@ -33571,7 +34053,7 @@ gawk -M 'BEGIN @{ n = 13; print (n + 0.0) % 2.0 @}' @end example Si pu@`o evitare completamente questo passaggio specificando il numero come -valore a virgola mobile fin dall'inizio: +valore in virgola mobile fin dall'inizio: @example gawk -M 'BEGIN @{ n = 13.0; print n % 2.0 @}' @@ -33585,7 +34067,7 @@ gawk -M 'BEGIN @{ n = 13; print n % 2 @}' @end example Dividendo due interi a precisione arbitraria con @samp{/} o con @samp{%}, il -risultato @`e tipicamente un valore a virgola mobile con precisione arbitraria +risultato @`e tipicamente un valore in virgola mobile con precisione arbitraria (a meno che il risultato non sia un numero intero esatto). @ifset INTDIV Per eseguire divisioni intere o calcolare moduli con interi a precisione @@ -33637,6 +34119,7 @@ che si @`e scelto di impostare: @example @c file eg/prog/pi.awk +@group # pi.awk --- calcola le cifre di pi @c endfile @c endfile @@ -33652,6 +34135,7 @@ che si @`e scelto di impostare: BEGIN @{ cifre = 100000 due = 2 * 10 ^ cifre +@end group pi = due for (m = cifre * 4; m > 0; --m) @{ d = m * 2 + 1 @@ -33762,11 +34246,16 @@ BEGIN @{ if (! adequate_math_precision(fpbits)) @{ print("Errore: la precisione di calcolo disponibile non basta.\n" \ "Provare ancora specificando l'argomento -M?") > "/dev/stderr" + # Nota: pu@`o essere necessario impostare un flag a questo punto + # per evitare di eseguire delle eventuali regole END exit 1 @} @} @end example +Occorre tener presente che @code{exit} eseguir@`a le regole @code{END}, +eventualmente contenute nel programma (@pxref{Istruzione exit}). + @node Problemi virgola mobile POSIX @section Confronto tra standard e uso corrente @@ -33782,12 +34271,12 @@ aggiuntive. Queste sono: @itemize @value{BULLET} @item -Interpretazione del valore dei dati a virgola mobile specificati in notazione +Interpretazione del valore dei dati in virgola mobile specificati in notazione esadecimale (p.es., @code{0xDEADBEEF}). (Da notare: valore dei dati letti, @emph{non} costanti facenti parte del codice sorgente.) @item -Supporto per i valori a virgola mobile speciali IEEE 754 ``not a number'' +Supporto per i valori in virgola mobile speciali IEEE 754 ``not a number'' (NaN), pi@`u infinito (``inf'') e meno infinito (``@minus{}inf''). In particolare, il formato per questi valori @`e quello specificato dallo standard C ISO 1999, che non distingue maiuscole/minuscole e pu@`o consentire @@ -33800,7 +34289,7 @@ dalla prassi consolidata: @itemize @value{BULLET} @item -Il manutentore di @command{gawk} crede che supportare i valori a virgola mobile +Il manutentore di @command{gawk} crede che supportare i valori in virgola mobile esadecimali, nello specifico, sia sbagliato, e che non sia mai stata intenzione dell'autore originale di introdurlo nel linguaggio. @@ -33818,7 +34307,7 @@ arrivati sin qui, ma non pensiamo che questo sia il posto dove volete essere.'' Recependo queste argomentazioni, e cercando nel contempo di assicurare la compatibilit@`a con le versioni precedenti dello standard, lo standard POSIX 2008 ha aggiunto delle formulazioni esplicite per consentire l'uso da parte di -@command{awk}, solo a richiesta, dei valori a virgola mobile esadecimali e +@command{awk}, solo a richiesta, dei valori in virgola mobile esadecimali e dei valori speciali ``@dfn{not a number}'' e infinito. @@ -33856,7 +34345,7 @@ e @samp{-nan} in modo speciale, producendo i corrispondenti valori numerici speciali. Il segno iniziale serve per segnalare a @command{gawk} (e all'utente) -che il valore @`e realmente numerico. I numeri a virgola mobile esadecimali +che il valore @`e realmente numerico. I numeri in virgola mobile esadecimali non sono consentiti (a meno di non usare anche @option{--non-decimal-data}, che @emph{non} @`e consigliabile). Per esempio: @@ -33864,7 +34353,7 @@ che @emph{non} @`e consigliabile). Per esempio: $ @kbd{echo nanny | gawk '@{ print $1 + 0 @}'} @print{} 0 $ @kbd{echo +nan | gawk '@{ print $1 + 0 @}'} -@print{} nan +@print{} +nan $ @kbd{echo 0xDeadBeef | gawk '@{ print $1 + 0 @}'} @print{} 0 @end example @@ -33873,6 +34362,15 @@ $ @kbd{echo 0xDeadBeef | gawk '@{ print $1 + 0 @}'} speciali. Cos@`{@dotless{i}}, @samp{+nan} e @samp{+NaN} sono la stessa cosa. @end itemize +Oltre a gestire l'input, @command{gawk} deve anche stampare valori +``corretti'' in output, quando un valore sia NaN o infinito. +A partire dalla @value{PVERSION} 4.2.2, per tali valori +@command{gawk} stampa una delle quattro stringhe sopra descritte: +@samp{+inf}, @samp{-inf}, @samp{+nan}, or @samp{-nan}. +Analogamente,se usato in modalit@`a POSIX, @command{gawk} stampa il risultato +della funzione C di sistema @code{printf()} usando la stringa di formato +@code{%g} per il valore, quale che esso sia. + @node Sommario virgola mobile @section Sommario @@ -33880,12 +34378,12 @@ speciali. Cos@`{@dotless{i}}, @samp{+nan} e @samp{+NaN} sono la stessa cosa. @item La maggior parte dell'aritmetica al calcolatore @`e fatta usando numeri interi oppure -valori a virgola mobile. L'@command{awk} standard usa valori a virgola mobile +valori in virgola mobile. L'@command{awk} standard usa valori in virgola mobile a doppia precisione. @item Nei primi anni '90 Barbie disse erroneamente, ``L'ora di matematica @`e -ostica!'' Sebbene la matematica non sia ostica, l'aritmetica a virgola +ostica!'' Sebbene la matematica non sia ostica, l'aritmetica in virgola mobile non @`e proprio come la matematica ``carta e penna'', e bisogna prestare attenzione: @@ -33926,7 +34424,7 @@ una pi@`u efficiente allocazione dello spazio rispetto all'uso di MPFR per eseguire gli stessi calcoli. @item -Ci sono diverse aree per quanto attiene ai numeri a virgola mobile in cui +Ci sono diverse aree per quanto attiene ai numeri in virgola mobile in cui @command{gawk} @`e in disaccordo con lo standard POSIX. @`E importante averlo ben presente. @@ -34362,7 +34860,7 @@ e sono gestite da @command{gawk} da quel punto in avanti. @item L'API definisce parecchie semplici @code{struct} che mappano dei valori come sono visti da @command{awk}. Un valore pu@`o essere un numero @code{double} -(a virgola mobile, in doppia precisione), una stringa o un +(in virgola mobile, in doppia precisione), una stringa o un vettore (come @`e il caso per i vettori multidimensionali o nella creazione di un nuovo vettore). @@ -34524,18 +35022,24 @@ e ogni campo @`e del tipo appropriato. L'uso di queste macro rende pi@`u facile da seguire l'accesso ai campi di @code{awk_value_t}. +@item enum AWK_NUMBER_TYPE @{ +@itemx @ @ @ @ AWK_NUMBER_TYPE_DOUBLE, +@itemx @ @ @ @ AWK_NUMBER_TYPE_MPFR, +@itemx @ @ @ @ AWK_NUMBER_TYPE_MPZ +@itemx @}; +La lista @code{enum} @`e usata nella struttura seguente per definire +il tipo di valore numerico con cui si ha a che fare. Va dichiarata al +livello pi@`u alto del file, in modo da poter essere usata sia con il +linguaggio C++ che con il C. + @item typedef struct awk_number @{ @itemx @ @ @ @ double d; -@itemx @ @ @ @ enum AWK_NUMBER_TYPE @{ -@itemx @ @ @ @ @ @ @ @ AWK_NUMBER_TYPE_DOUBLE, -@itemx @ @ @ @ @ @ @ @ AWK_NUMBER_TYPE_MPFR, -@itemx @ @ @ @ @ @ @ @ AWK_NUMBER_TYPE_MPZ -@itemx @ @ @ @ @} type; +@itemx @ @ @ @ enum AWK_NUMBER_TYPE type; @itemx @ @ @ @ void *ptr; @itemx @} awk_number_t; Questo rappresenta un valore numerico. Internamente, @command{gawk} memorizza ogni numero o come una variabile C di tipo @code{double}, -o come un numero intero GMP, o come un numero MPFR a virgola mobile +o come un numero intero GMP, o come un numero MPFR in virgola mobile di precisione arbitraria. Per consentire alle estensioni di supportare valori numerici GMP ed MPFR, i valori numerici sono trasmessi utilizzando questa struttura. @@ -34544,10 +35048,9 @@ L'elemento in doppia-precisione @code{d} @`e sempre presente nei dati ricevuti da @command{gawk}. Inoltre, esaminando il membro @code{type}, un'estensione @`e in grado di determinare se il membro puntato da @code{ptr} sia un numero intero GMP (tipo @code{mpz_ptr}), o un numero -MPFR a virgola mobile (tipo @code{mpfr_ptr_t}), e trasformarlo a seconda +MPFR in virgola mobile (tipo @code{mpfr_ptr_t}), e trasformarlo a seconda delle necessit@`a. - @item typedef void *awk_scalar_t; La variabili scalari possono essere rappresentate da un tipo opaco. Questi valori sono ottenuti da @command{gawk} e in seguito gli vengono restituiti. @@ -34756,15 +35259,18 @@ Questo @`e solitamente il nome della funzione che sta usando la macro. Per esempio, si potrebbe allocare il valore di una stringa cos@`{@dotless{i}}: @example +@group awk_value_t risultato; char *message; -const char greet[] = "non v'allarmate!"; +const char greet[] = "Non v'allarmate!"; emalloc(message, char *, sizeof(greet), "myfunc"); strcpy(message, greet); make_malloced_string(message, strlen(message), & risultato); +@end group @end example +@sp 2 @item #define ezalloc(pointer, type, size, message) @dots{} Questo @`e simile a @code{emalloc()}, ma chiama @code{gawk_calloc()} invece che @code{gawk_malloc()}. @@ -34799,9 +35305,9 @@ senza il supporto MPFR, chiamare questa funzione genera un errore fatale. Entrambe queste funzioni restituiscono un codice di ritorno @samp{void *}, poich@'e il file di intestazione @file{gawkapi.h} non dovrebbe avere dipendenze da @code{<mpfr.h>} (e @code{<gmp.h>}, -che @`e incluso da @code{<mpfr.h>}). I valori di ritorno effettivamente +che @`e incluso da @code{<mpfr.h>}). I codici di ritorno effettivamente restituiti sono di tipo @code{mpfr_ptr} e @code{mpz_ptr} rispettivamente, -e si dovrebbero assegnare in maniera appropriata questi valori di ritorno +e si dovrebbero assegnare in maniera appropriata questi codici di ritorno prima di assegnare i risultati a variabili del tipo corretto. @node Funzioni di costruzione @@ -34916,6 +35422,7 @@ registrare parti di un'estensione con @command{gawk}. Le funzioni di estensione sono descritte dal seguente tracciato record: @example +@group typedef struct awk_ext_func @{ @ @ @ @ const char *name; @ @ @ @ awk_value_t *(*const function)(int num_actual_args, @@ -34927,6 +35434,7 @@ typedef struct awk_ext_func @{ @ @ @ @ void *data; /* puntatore di tipo opaco @ @ @ @ a ogni informazione ulteriore */ @} awk_ext_func_t; +@end group @end example I campi sono: @@ -35147,6 +35655,7 @@ L'estensione dovrebbe raccogliere queste funzioni all'interno di una struttura @code{awk_input_parser_t}, simile a questa: @example +@group typedef struct awk_input_parser @{ const char *name; /* nome dell'analizzatore */ awk_bool_t (*can_take_file)(const awk_input_buf_t *iobuf); @@ -35154,6 +35663,7 @@ typedef struct awk_input_parser @{ awk_const struct awk_input_parser *awk_const next; /* per uso di gawk */ @} awk_input_parser_t; +@end group @end example I campi sono: @@ -35980,6 +36490,7 @@ che un accesso @`e necessario. Questo argomento @`e gi@`a stato trattato in precedenza, nella @ref{Tipi di dati generali}. +@need 1500 Le funzioni seguenti servono per gestire gli @dfn{scalar cookie}: @table @code @@ -36050,12 +36561,14 @@ uno @dfn{scalar cookie} per la variabile usando @code{sym_lookup()}: @example +@group static awk_scalar_t magic_var_cookie; /* cookie per MAGIC_VAR */ static void inizializza_estensione() @{ awk_value_t valore; +@end group /* immettere il valore iniziale */ sym_update("MAGIC_VAR", make_number(42.0, & valore)); @@ -36464,7 +36977,7 @@ costituisce la funzione @code{dump_array_and_delete()}. @`E stato leggermente modificato per facilitare l'esposizione. -La prima parte dichiara variabili, imposta il valore di ritorno di default +La prima parte dichiara variabili, imposta il codice di ritorno di default in @code{risultato}, e controlla che la funzione sia stata chiamata con il numero corretto di argomenti: @@ -36606,10 +37119,12 @@ Infine, poich@'e tutto @`e andato bene, la funzione imposta il codice di ritorno a "successo", e lo restituisce quando esce: @example +@group make_number(1.0, risultato); out: return risultato; @} +@end group @end example Ecco l'output ottenuto eseguendo questa parte del test: @@ -36829,7 +37344,7 @@ BEGIN @{ Ecco il risultato dell'esecuzione dello script: @example -$ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk} +$ @kbd{AWKLIBPATH=$PWD gawk -f subarray.awk} @print{} new_array["sottovettore"]["pippo"] = pluto @print{} new_array["salve"] = mondo @print{} new_array["risposta"] = 42 @@ -36986,7 +37501,7 @@ Dipende dall'estensione decidere se ci sono incompatibilit@`a con l'API. Tipicamente, basta un controllo di questo tipo: @example -if (api->major_version != GAWK_API_MAJOR_VERSION +if ( api->major_version != GAWK_API_MAJOR_VERSION || api->minor_version < GAWK_API_MINOR_VERSION) @{ fprintf(stderr, "estensione_pippo: discordanza di versione \ con gawk!\n"); @@ -37106,10 +37621,12 @@ standard, come descritto qui sotto. Il codice predefinito in questione @`e anche descritto nel file di intestazione @file{gawkapi.h}: @example +@group /* Codice predefinito: */ int plugin_is_GPL_compatible; static gawk_api_t *const api; +@end group static awk_ext_id_t ext_id; static const char *ext_version = NULL; /* o @dots{} = "qualche stringa" */ @@ -37236,6 +37753,49 @@ compilazione, l'API rimane compatibile a livello di codice sorgente con la precedente versione API. Le differenze pi@`u rilevanti sono gli ulteriori campi nella struttura @code{awk_ext_func_t}, e l'aggiunta del terzo argomento nella funzione di implementazione in linguaggio C. +(@pxref{Funzioni di estensione}). + +Quella che segue @`e una lista di singole funzionalit@`a che sono +state modificate nella versione 2 rispetto alla versione 1 dell'API: + +@itemize @bullet + +@item +I valori numerici possono ora essere anche di tipo MPFR/MPZ +(@pxref{Tipi di dati generali}). + +@item +Ci sono nuovi tipi di stringa: @code{AWK_REGEX} e @code{AWK_STRNUM} +(@pxref{Tipi di dati generali}). + +@item +@`E disponibile la nuova macro @code{ezalloc()} +(@pxref{Funzioni di allocazione memoria}). + +@item +La struttura @code{awk_ext_func_t} @`e stata modificata. Invece del +parametro @code{num_expected_args}, ha ora i due parametri +@code{max_expected} e @code{min_required} +(@pxref{Funzioni di estensione}). + +@item +In @code{get_record()}, un analizzatore di input pu@`o ora specificare +l'ampiezza dei campi +(@pxref{Analizzatori di input}). + +@item +Le estensioni possono ora inviare messaggi di errore non fatali +(@pxref{Stampare messaggi}). + +@item +Quando di appiattisce un vettore, si pu@`o ora specificare il tipo +dell'indice e quello dei valori +(@pxref{Funzioni per i vettori}). + +@item +C'@`e una nuova API, @code{get_file()} +(@pxref{Ridirezione API}). +@end itemize @node Trovare le estensioni @section Come @command{gawk} trova le estensioni compilate @@ -37502,11 +38062,13 @@ Il secondo @`e un puntatore a una struttura @code{awk_value_t}, normalmente chiamata @code{risultato}: @example +@group /* do_chdir --- fornisce funzione chdir() caricata dinamicamente per gawk */ static awk_value_t * do_chdir(int nargs, awk_value_t *risultato, struct awk_ext_func *non_usata) +@end group @{ awk_value_t newdir; int ret = -1; @@ -37641,7 +38203,7 @@ fill_stat_array(const char *name, awk_array_t vettore, struct stat *sbuf) #endif #ifdef S_IFDOOR /* Stranezza Solaris */ @{ S_IFDOOR, "door" @}, -#endif /* S_IFDOOR */ +#endif @}; int j, k; @end example @@ -37683,9 +38245,11 @@ certi campi e/o il tipo del file. Viene poi restituito zero, per indicare che tutto @`e andato bene: @example +@group #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE array_set_numeric(vettore, "blksize", sbuf->st_blksize); -#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ +#endif +@end group pmode = format_mode(sbuf->st_mode); array_set(vettore, "pmode", make_const_string(pmode, strlen(pmode), @@ -37781,10 +38345,12 @@ Poi, ottiene le informazioni relative al file. Se la funzione chiamata in caso di errore, imposta ERRNO e ritorna */ ret = statfunc(name, & sbuf); +@group if (ret < 0) @{ update_ERRNO_int(errno); return make_number(ret, risultato); @} +@end group @end example Il lavoro noioso @`e svolto da @code{fill_stat_array()}, visto in @@ -37792,10 +38358,12 @@ precedenza. Alla fine, la funzione restituisce il codice di ritorno impostato da @code{fill_stat_array()}: @example +@group ret = fill_stat_array(name, vettore, & sbuf); return make_number(ret, risultato); @} +@end group @end example Infine, @`e necessario fornire la ``colla'' che aggrega @@ -38258,7 +38826,7 @@ Nel processo figlio, gli elementi @code{PROCINFO["pid"]} e @cindex estensione @code{waitpid()} @item ret = waitpid(pid) Questa funzione ha un unico argomento numerico, l'identificativo del processo -di cui aspettare l'esito. Il valore di ritorno @`e quello restituito dalla +di cui aspettare l'esito. Il codice di ritorno @`e quello restituito dalla chiamata di sistema @code{waitpid()}. @cindex @code{wait()}, estensione @@ -38678,7 +39246,7 @@ Questo @`e il modo per caricare l'estensione. @cindex estensione @code{gettimeofday()} @item ora_corrente = gettimeofday() Restituisce il numero di secondi trascorsi dalle ore 00:00 del giorno -01/01/1970 UTC come valore a virgola mobile. +01/01/1970 UTC come valore in virgola mobile. Se questa informazione non @`e disponibile nella piattaforma in uso, restituisce @minus{}1 e imposta @code{ERRNO}. Il valore fornito dovrebbe avere la precisione di una frazione di @@ -38697,7 +39265,7 @@ specificati. Se @var{secondi} ha un valore negativo, o la chiamata di sistema non riesce, restituisce @minus{}1 e imposta @code{ERRNO}. In caso contrario, restituisce zero dopo aver lasciato trascorrere la quantit@`a di tempo indicata. -Si noti che @var{secondi} pu@`o essere un numero a virgola mobile (non solo un +Si noti che @var{secondi} pu@`o essere un numero in virgola mobile (non solo un numero intero). Dettagli di implementazione: a seconda della disponibilit@`a nel sistema in uso, questa funzione tenta di usare @code{nanosleep()} o @code{select()} per @@ -38730,31 +39298,28 @@ fornisce varie estensioni per @command{gawk}, compresa una per l'elaborazione dei file XML. Questa @`e un'evoluzione del progetto noto come @command{xgawk} (XML @command{gawk}). -Al momento della stesura di questo testo, ci sono otto estensioni: +Le estensioni sono parecchie. Alcune delle pi@`u interessanti sono: @itemize @value{BULLET} @item -Estensione @code{errno} - -@item -Estensione GD graphics library +Estensione @code{abort}. Consente di uscire immediatamente dal programma +@command{awk} senza eseguire le regole @code{END}. @item -Estensione libreria MPFR -(fornisce l'accesso a varie funzioni MPFR non previste dal supporto nativo -di MPFR disponibile in @command{gawk}) +Estensione @code{json}. +Permette di serializzare un vettore multidimensionale trasformandolo in +una stringa in formato JSON (JavaScript Object Notation), di effettuare +l'operazione inversa, de-serializzando una stringa JSON, generando +un vettore @command{gawk}. @item -Estensione PDF +Estensione libreria MPFR. +Fornisce accesso a varie funzioni MPFR non previste dal supporto nativo +di MPFR disponibile in @command{gawk} @item -Estensione PostgreSQL - -@item -Estensione Redis - -@item -Estensione Select +Estensione Select. Fornisce delle funzionalit@`a, appoggiandosi sulla +chiamata di sistema @code{select()}. @item Estensione analizzatore XML, usando la libreria di analisi XML @@ -38772,6 +39337,11 @@ Il comando per farlo @`e il seguente: git clone git://git.code.sf.net/p/gawkextlib/code gawkextlib-code @end example +@cindex RapidJson, libreria per analizzare JSON +@cindex JSON, RapidJson, libreria per analizzare +Occorre che sia installata la libreria di analisi JSON +per poter generare e usare l'estensione @code{json}. + @cindex Expat, libreria per analizzare XML @cindex XML, Expat, libreria per analizzare Per poter compilare e usare l'estensione XML, @`e necessario installare @@ -39206,7 +39776,7 @@ Le sequenze di protezione @samp{\a}, @samp{\v} e @samp{\x} @c GNU, for ANSI C compat @item -Un valore di ritorno definito per la funzione predefinita @code{srand()} +Un codice di ritorno definito per la funzione predefinita @code{srand()} (@pxref{Funzioni numeriche}) @item @@ -40394,7 +40964,7 @@ La versione 4.2 di @command{gawk} ha introdotto le seguenti modifiche: @itemize @bullet @item -Differenze apportate alle variabili di ambiente (@code{ENVIRON}) sono +Differenze apportate alle variabili d'ambiente (@code{ENVIRON}) sono riflesse in quelle rese disponibili a @command{gawk} e in quelle di programmi che siano da esso richiamati. @xref{Variabili auto-assegnate}. @@ -40517,6 +41087,14 @@ Il supporto per GNU/Linux sull'architettura Alpha @`e stato rimosso. @end itemize +La @value{PVERSION} 5.0 ha aggiunto le seguenti funzionalit@`a: + +@itemize +@item +L'elemento di vettore @code{PROCINFO["platform"]}, che permette di +scrivere del codice che tiene conto di piattaforma / sistema operativo. +@end itemize + @c XXX ADD MORE STUFF HERE @end ifclear @@ -41139,7 +41717,7 @@ correzioni a errori minori sono state incluse nel rilascio. Il @dfn{patch level} corrente @`e @value{PATCHLEVEL}, ma quando ci si procura una distribuzione, andr@`a ottenuta quella con il livello pi@`u alto di versione, rilascio e @dfn{patch}. -(Si noti, comunque, che livelli di @dfn{patch} maggiori o uguali a 70 +(Si noti, comunque, che livelli di @dfn{patch} maggiori o uguali a 60 denotano versioni ``beta'', ossia versioni non destinate a essere usate in produzione; non si dovrebbero utilizzare tali versioni, se non si @`e disposti a sperimentare.) @@ -41367,7 +41945,7 @@ gli esempi di estensione incluse con @command{gawk}. Ulteriori file, non-essenziali. Al momento, questa directory contiene alcuni file da eseguire al momento di iniziare una sessione, da installare nella directory @file{/etc/profile.d} -per essere di aiuto nella gestione delle variabili di ambiente +per essere di aiuto nella gestione delle variabili d'ambiente @env{AWKPATH} e @env{AWKLIBPATH}. @xref{File da usare a inizio sessione}, per ulteriori informazioni. @@ -41501,7 +42079,7 @@ utenti che possono utilizzare il comando @command{sudo}. La distribuzione contiene i file da usare a inizio sessione @file{gawk.sh} e @file{gawk.csh}, che contengono funzioni che possono essere di aiuto -nel gestire le variabili di ambiente +nel gestire le variabili d'ambiente @env{AWKPATH} e @env{AWKLIBPATH}. Su un sistema Fedora GNU/Linux, questi file dovrebbero essere installati nella directory @file{/etc/profile.d}; @@ -41558,7 +42136,7 @@ quando si compila @command{gawk} a partire dai sorgenti, tra cui: @cindex @option{--disable-extensions}, opzione di configurazione @cindex opzione di configurazione @code{--disable-extensions} @item --disable-extensions -Richiede di non configurare e generare le estensioni di esempio nella +Richiesta di non configurare e generare le estensioni di esempio nella directory @file{extension}. Questo @`e utile quando si genera @command{gawk} per essere eseguito su un'altra piattaforma. L'azione di default @`e di controllare dinamicamente se le estensioni @@ -41567,7 +42145,7 @@ possono essere configurate e compilate. @cindex @option{--disable-lint}, opzione di configurazione @cindex opzione di configurazione @code{--disable-lint} @item --disable-lint -Disabilita i controlli @dfn{lint} all'interno di @command{gawk}. Le opzioni +Disabilitare i controlli @dfn{lint} all'interno di @command{gawk}. Le opzioni @option{--lint} e @option{--lint-old} (@pxref{Opzioni}) sono accettate, ma non fanno nulla, e non emettono alcun messaggio di @@ -41592,7 +42170,7 @@ Quest'opzione potr@`a essere rimossa in futuro. @cindex @option{--disable-mpfr}, opzione di configurazione @cindex opzione di configurazione @code{--disable-mpfr} @item --disable-mpfr -Non viene effettuato il controllo delle librerie MPFR e GMP. +Non effettuare il controllo delle librerie MPFR e GMP. Ci@`o pu@`o essere utile principalmente per gli sviluppatori, per assicurarsi che tutto funzioni regolarmente nel caso in cui il supporto MPFR non sia disponibile. @@ -41600,16 +42178,19 @@ il supporto MPFR non sia disponibile. @cindex @option{--disable-nls}, opzione di configurazione @cindex opzione di configurazione @code{--disable-nls} @item --disable-nls -Non attiva la traduzione automatica dei messaggi. +Non attivare la traduzione automatica dei messaggi. Ci@`o normalmente non @`e consigliabile, ma pu@`o apportare qualche lieve miglioramento nei tempi di esecuzione di un programma. -@cindex @option{--with-whiny-user-strftime}, opzione di configurazione -@cindex opzione di configurazione @code{--with-whiny-user-strftime} -@item --with-whiny-user-strftime -Forza l'uso della versione della funzione C @code{strftime()} inclusa nella -distribuzione di @command{gawk}, per i sistemi in cui la funzione stessa -non sia disponibile. +@cindex @option{--enable-versioned-extension-dir}, opzione di configurazione +@cindex opzione di configuzazione @code{--enable-versioned-extension-dir} +@item --enable-versioned-extension-dir +Usare una directory con l'indicazione della versione per le estensioni. +Il nome della directory conterr@`a la versione principale e quella +secondaria dell'API. Ci@`o consente la presenza, nello stesso sistema, +di pi@`u di una versione dell'API, senza che fra di esse sorgano dei +conflitti legati all'una o all'altra versione. + @end table Si usi il comando @samp{./configure --help} per ottenere la lista completa @@ -41741,9 +42322,10 @@ usando gli strumenti MinGW, scrivere @samp{make mingw32}. @cindex PC, @command{gawk} su sistemi operativi @cindex sistemi operativi PC, @command{gawk} su -Sotto MS-Windows, gli ambienti Cygwin e MinGW consentono di usare +Sotto MS-Windows, l'ambiente MinGW consente di usare sia l'operatore @samp{|&} che le operazioni su rete TCP/IP (@pxref{Reti TCP/IP}). +L'ambiente DJGPP non consente di usare @samp{|&}. @cindex percorso di ricerca @cindex percorso di ricerca per file sorgente @@ -41804,6 +42386,13 @@ un'appropriata opzione @samp{-v BINMODE=@var{N}} sulla riga di comando. @code{BINMODE} @`e impostato nel momento in cui un file o @dfn{pipe} @`e aperto e non pu@`o essere cambiato in corso di elaborazione. +Su sistemi compatibili con POSIX, il valore di queta variabile non ha +alcun effetto. Pertanto, se si pensa che un dato programma sar@`a eseguito +su parecchi sistemi differenti, e che sia necessario usare +@code{BINMODE}, @`e possibile impostarlo semplicemente (nel programma +o sulla riga di comando) incondizionatamente, senza preoccuparsi del +sistema operativo sotto il quale il programma viene eseguito. + Il nome @code{BINMODE} @`e stato scelto in analogia con @command{mawk} (@pxref{Altre versioni}). @command{mawk} e @command{gawk} gestiscono @code{BINMODE} in maniera simile; @@ -41874,8 +42463,17 @@ make && make check @end example In confronto a un sistema GNU/Linux sulla stessa macchina, l'esecuzione -del passo di @samp{configure} sotto Cygwin richiede molto pi@`u tempo. Tuttavia -si conclude regolarmente, e poi @samp{make} funziona come ci si aspetta. +del passo di @samp{configure} sotto Cygwin richiede molto pi@`u tempo. +Tuttavia si conclude regolarmente, e poi @samp{make} funziona come ci si +aspetta. + +Le versioni pi@`u recenti di Cygwin aprono tutti i file in modalit@`a binaria. +Ci@`o implica che si dovrebbe usare @samp{RS = "\r?\n"} per riuscire a +gestire file di testo MS-Windows in formato standard, in cui ogni riga +termina con i due caratteri di ritorno a capo e avanzamento riga. + +L'ambiente Cygwin consente l'utilizzo sia dell'operatore @samp{|&} +che di reti TCP/IP (@pxref{Reti TCP/IP}). @node MSYS @appendixsubsubsec Usare @command{gawk} in ambiente MSYS @@ -42150,8 +42748,9 @@ unix_status = (vms_status .and. %x7f8) / 8 Un programma C che usa @code{exec()} per chiamare @command{gawk} ricever@`a il valore originale della exit in stile Unix. -Precedenti versioni di @command{gawk} per VMS consideravano un codice di -ritorno a Unix di 0 come 1, un errore come 2, un errore fatale come 4, e tutti +Precedenti versioni di @command{gawk} per VMS consideravano un +codice di ritorno a Unix di 0 come 1, un errore come 2, +un errore fatale come 4, e tutti gli altri valori erano restituiti immodificati. Questa era una violazione rispetto alle specifiche di codifica delle condizioni di uscita di VMS. @@ -42386,6 +42985,13 @@ domande riguardo a qualcosa di non chiaro nella documentazione o a proposito di funzionalit@`a oscure, si scriva alla mailing list dei bug; si prover@`a a essere di aiuto nei limiti del possibile. +Si tenga presente: Si chiede di seguire le +@uref{https://gnu.org/philosophy/kind-communication.html, +@dfn{GNU Kind Communication Guidelines} +-- Linee guida GNU per una comunicazione gentile} +nella corrispondenza con la lista +(e anche in quella fuori dalla lista). + @node Usenet @appendixsubsec Non segnalare bug a USENET! @@ -42411,7 +43017,12 @@ Sebbene alcuni degli sviluppatori di @command{gawk} leggano talora i messaggi di questo gruppo di discussione, il manutentore principale di @command{gawk} non lo fa pi@`u. Quindi @`e praticamente certo che un messaggio inviato l@`a @emph{non} sia da lui letto. -La procedura qui descritta @`e la sola maniera ufficialmente riconosciuta + +Analogamente, segnalando bug o ponendo domande in @dfn{forum} online +come @uref{https://stackoverflow.com/, Stack Overflow}) si pu@`o +ottenere una risposta, ma non dai manutentori di @command{gawk}, +che non dedicano tempo ai @dfn{forum} online. La procedura qui +descritta @`e la sola maniera ufficialmente riconosciuta per notificare problemi. Davvero! @ignore @@ -42480,13 +43091,6 @@ nel caso che qualche volontario desideri prenderla in carico. Se questo non dovesse succedere, la parte di codice relativa questa versione sar@`a rimossa dalla distribuzione. -@c 7/2017, Juan Guerrero has taken over the DJGPP port. -@ignore -The DJGPP port is no longer supported; it will remain in the code base -for a while in case a volunteer wishes to take it over. If this does -not happen, then eventually code for this port will be removed. -@end ignore - @node Altre versioni @appendixsec Altre implementazioni di @command{awk} liberamente disponibili @cindex @command{awk}, implementazioni di @@ -42531,38 +43135,25 @@ Questa @value{SECTION} descrive in breve dove @`e possibile trovarle: @item Unix @command{awk} Brian Kernighan, uno degli sviluppatori originali di Unix @command{awk}, ha reso disponibile liberamente la sua implementazione di @command{awk}. -Si pu@`o scaricare questa versione dalla -@uref{http://www.cs.princeton.edu/~bwk, sua pagina principale}. -@`E disponibile in parecchi formati compressi: - -@table @asis -@item Archivio Shell -@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.shar} - -@item File @command{tar} compresso -@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.tar.gz} - -@item File Zip -@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.zip} -@end table - -@cindex @command{git}, programma di utilit@`a -@cindex programma di utilit@`a @command{git} -@`E anche disponbile in GitHub: - +Pu@`o essere scaricata da GitHub: @example git clone git://github.com/onetrueawk/awk bwkawk @end example @noindent Questo comando crea una copia del deposito @uref{https://git-scm.com, Git} -in una directory chiamata @file{bwkawk}. Se si omette questo argomento della -riga di comando @command{git}, la copia del deposito @`e creata nella +in una directory chiamata @file{bwkawk}. Se si omette l'ultimo argomento +della riga di comando @command{git}, la copia del deposito @`e creata in una directory di nome @file{awk}. Questa versione richiede un compilatore ISO C (standard 1990); il compilatore C contenuto in GCC (la collezione di compilatori GNU) @`e pi@`u che sufficiente. +Per eseguire la compilazione, si rivedano le impostazioni nel file +@file{makefile}, e quindi si richiami semplicemente @command{make}. +Si noti che il risultato della compilazione ha come nome +@command{a.out}; questo file va rinominato in maniera adeguata. + @xref{Estensioni comuni} per una lista di estensioni in questo @command{awk} che non sono in POSIX @command{awk}. @@ -42686,6 +43277,19 @@ il progetto mette a disposizione questa implementazione. Si possono vedere i singoli file in @uref{https://github.com/joyent/illumos-joyent/blob/master/usr/src/cmd/awk_xpg4}. +@cindex @command{goawk} +@cindex Go, implementazione di @command{awk} +@cindex sorgente, @command{goawk} +@cindex @command{goawk}, sorgente di +@item @command{goawk} +Questo @`e un interpretatore di @command{awk} scritto nel +@uref{https://golang.org/, Linguaggio di programmazion Go}. +Implementa POSIX @command{awk}, con alcune estensioni minori. +Il codice sorgente @`e disponibile in @uref{https://github.com/benhoyt/goawk}. +L'autore ha scritto un buon +@uref{https://benhoyt.com/writings/goawk/, articolo} +che descrive l'implementazione. + @cindex @command{jawk} @cindex Java, implementazione di @command{awk} @cindex implementazione Java di @command{awk} @@ -42810,8 +43414,6 @@ specificatamente a @command{gawk} e non ad altre implementazioni. * Limitazioni dell'implementazione:: Alcune limitazioni dell'implementazione. * Progetto delle estensioni:: Note di progetto sull'estensione API. -* Meccanismo delle vecchie estensioni:: Alcune compatibilit@`a per le vecchie - estensioni. * Sommario delle note:: Sommario delle note di implementazione. @end menu @@ -43523,7 +44125,7 @@ sistemi operativi possono avere limiti differenti. @item Numero di record in input in un singolo file @tab @code{MAX_LONG} @item Numero totale di record in input @tab @code{MAX_LONG} @item Numero di ridirezioni via @dfn{pipe} @tab min(numero processi per utente, numero di file aperti) -@item Valori numerici @tab Numeri a virgola mobile in doppia precisione (se non si usa la funzionalit@`a MPFR) +@item Valori numerici @tab Numeri in virgola mobile in doppia precisione (se non si usa la funzionalit@`a MPFR) @item Dimensione di un campo @tab @code{MAX_INT} @item Dimensione di una stringa letterale @tab @code{MAX_INT} @item Dimensione di una stringa di @dfn{printf} @tab @code{MAX_INT} @@ -43774,54 +44376,6 @@ evitare in questo modo possibili conflitti nei nomi di funzione. Naturalmente, al momento in cui queste righe sono state scritte, nessuna decisione @`e stata presa riguardo ai punti sopra descritti. -@node Meccanismo delle vecchie estensioni -@appendixsec Compatibilit@`a per le vecchie estensioni - -@iftex -Il -@end iftex -@ref{Estensioni dinamiche}, descrive le API supportate e i meccanismi -per scrivere estensioni per @command{gawk}. Quest'API @`e stata introdotta -nella @value{PVERSION} 4.1. Peraltro, gi@`a da molti anni @command{gawk} -metteva a disposizione un meccanismo di estensione che richiedeva una -familiarit@`a con la struttura interna di @command{gawk} e che non era stato -progettato altrettanto bene. - -Per garantire un periodo di transizione, @command{gawk} @value{PVERSION} 4.1 -continua a supportare il meccanismo di estensione originale. -Questo rimarr@`a disponibile per la durata di una sola versione principale. -Il supporto cesser@`a, e sar@`a rimosso dal codice sorgente, al rilascio -della prossima versione principale. - -In breve, le estensioni in stile originale dovrebbero essere compilate -includendo il file di intestazione @file{awk.h} nel codice sorgente -dell'estensione. Inoltre, va definito l'identificativo @samp{GAWK} durante la -preparazione (si usi @samp{-DGAWK} con compilatori in stile Unix). Se non lo -si fa, le definizioni in @file{gawkapi.h} risulteranno in conflitto con quelle -in @file{awk.h} e l'estensione non sar@`a compilabile. - -Come nelle versioni precedenti, un'estensione vecchio stile sar@`a caricata -usando la funzione predefinita @code{extension()} (che non viene ulteriormente -documentata). Questa funzione, a sua volta, trova e carica il file oggetto -condiviso che contiene l'estensione e chiama la sua routine C @code{dl_load()}. - -Poich@'e le estensioni in stile originale e quelle nello stile nuovo usano -differenti routine di inizializzazione(@code{dl_load()} e @code{dlload()}, -rispettivamente), esse possono tranquillamente essere installate nella stessa -directory (il cui nome deve essere contenuto nella variabile @env{AWKLIBPATH}) -senza problemi di conflitti. - -Il @dfn{team} di sviluppo di @command{gawk} raccomanda caldamente di convertire -ogni estensione del vecchio tipo ancora in uso, in modo da utilizzare la nuova -API descritta -@iftex -nel -@end iftex -@ifnottex -in -@end ifnottex -@ref{Estensioni dinamiche}. - @node Sommario delle note @appendixsec Sommario @@ -44062,11 +44616,11 @@ variabili numeriche e di tipo stringa, sono definite come valori La @end iftex @ref{Aritmetica del computer}, ha fornito un'introduzione di base ai tipi -numerici (interi e a virgola mobile) e a come questi sono usati in un computer. +numerici (interi e in virgola mobile) e a come questi sono usati in un computer. Si consiglia di rileggere quelle informazioni, comprese le numerose avvertente l@`a esposte. -@cindex stringhe nulle +@cindex stringa nulla Mentre @`e probabile che ci si sia abituati all'idea di un numero senza un valore (cio@`e, allo zero), richiede un po' pi@`u di riflessione abituarsi all'idea di dati di tipo carattere a lunghezza zero. Nonostante ci@`o, questo tipo di dato @@ -44076,14 +44630,30 @@ programmi @command{awk}: @code{""}. Gli esseri umani sono abituati a usare il sistema decimale, cio@`e a base 10. In base 10, i numeri vanno da 0 a 9, e poi ``vengono riportati'' nella -colonna successiva. (Chi si ricorda la scuola elementare? 42 = 4 x 10 + 2.) +colonna +@iftex +colonna successiva. +(Chi si ricorda la scuola elementare? @math{42 = 4 volte 10 + 2}.) +@end iftex +@ifnottex +colonna successiva. +(Chi si ricorda la scuola elementare? 42 = 4 x 10 + 2.) +@end ifnottex Ma esistono anche altre basi per i numeri. I computer normalmente usano la base 2 o @dfn{binaria}, la base 8 o @dfn{ottale}, e la base 16 o @dfn{esadecimale}. Nella numerazione binaria, ogni colonna rappresenta il doppio del valore della colonna alla sua destra. Ogni colonna pu@`o contenere -solo uno 0 o un 1. Quindi, il numero binario 1010 rappresenta (1 x 8) + (0 x -4) + (1 x 2) + (0 x 1), ossia il numero decimale 10. Le numerazioni ottale ed +solo uno 0 o un 1. +@iftex +Quindi, il numero binario 1010 rappresenta @math{(1 volta 8) + (0 volte 4) ++ (1 volta 2) + (0 volte 1)}, ossia il numero decimale 10. +@end iftex +@ifnottex +Quindi, il numero binario 1010 rappresenta (1 x 8) + (0 x 4) ++ (1 x 2) + (0 x 1), ossia il numero decimale 10. +@end ifnottex +Le numerazioni ottale ed esadecimale sono trattate pi@`u ampiamente @ifnottex in @@ -44236,7 +44806,13 @@ i circuiti elettronici funzionano ``naturalmente'' in base 2 calcolata usando la base 2. Ciascuna cifra rappresenta la presenza (o l'assenza) di una potenza di 2 ed @`e chiamata un @dfn{bit}. Cos@`{@dotless{i}}, per esempio, il numero in base due @code{10101} rappresenta il -numero in base decimale 21, ((1 x 16) + (1 x 4) + (1 x 1)). +numero in base decimale 21, +@iftex +(@math{(1 volta 16) + (1 volta 4) + (1 volta 1)}). +@end iftex +@ifnottex +((1 x 16) + (1 x 4) + (1 x 1)). +@end ifnottex Poich@'e i numeri in base due diventano rapidamente molto lunghi sia da leggere che da scrivere, normalmente li si unisce a gruppi di tre @@ -44303,9 +44879,9 @@ Abbreviazione di ``Binary Digit'' [cifra binaria]. Tutti i valori nella memoria di un computer sono rappresentati nella forma di cifre binarie: valori che sono zero o uno. Gruppi di bit possono essere interpretati differentemente---come numeri -interi, numeri a virgola mobile, dati di tipo carattere, indirizzi di altri +interi, numeri in virgola mobile, dati di tipo carattere, indirizzi di altri oggetti contenuti in memoria, o altri dati ancora. -@command{awk} permette di lavorare con numeri a virgola mobile e stringhe. +@command{awk} permette di lavorare con numeri in virgola mobile e stringhe. @command{gawk} permette di manipolare bit con le funzioni predefinite descritte @ifnottex @@ -44346,7 +44922,7 @@ stile complessivo, che @`e abbastanza simile a quello del linguaggio C. La C shell non @`e compatibile all'indietro con la Bourne Shell, e per questo motivo un'attenzione speciale @`e necessaria se si convertono alla C shell degli script scritti per altre shell Unix, in particolare per ci@`o che -concerne la gestione delle variaili di shell. +concerne la gestione delle variabili di shell. Si veda anche ``Bourne Shell''. @item C++ @@ -44484,7 +45060,13 @@ le lettere @code{A}--@code{F}, con @samp{A} che rappresenta 10, @samp{B} che rappresenta 11, e cos@`{@dotless{i}} via, fino a @samp{F} per 15. I numeri esadecimali sono scritti in C prefissandoli con @samp{0x}, -per indicarne la base. Quindi, @code{0x12} @`e 18 ((1 x 16) + 2). +per indicarne la base. +@iftex +Quindi, @code{0x12} @`e 18 (@math{(1 volta 16) + 2}). +@end iftex +@ifnottex +Quindi, @code{0x12} @`e 18 ((1 x 16) + 2). +@end ifnottex @xref{Numeri non-decimali}. @item Espressione booleana @@ -44578,7 +45160,7 @@ Si veda anche ``Espressioni regolari''. La negazione di una @dfn{espressione tra parentesi quadre}. Tutto ci@`o che @emph{non} @`e descritto da una data espressione tra parentesi quadre. Il simbolo @samp{^} precede l'espressione tra parentesi quadre che viene -negata. Per esempio: @samp{[[^:digit:]} +negata. Per esempio: @samp{[^[:digit:]]} designa qualsiasi carattere che non sia una cifra. @samp{[^bad]} designa qualsiasi carattere che non sia una delle lettere @samp{b}, @samp{a}, o @samp{d}. @@ -44860,11 +45442,11 @@ Un'operazione che non fa nulla. @item Numero Un dato oggetto il cui valore @`e numerico. Le implementazioni di @command{awk} -usano numeri a virgola mobile in doppia precisione per rappresentare i numeri. -Le primissime implementazioni di @command{awk} usavano numeri a virgola mobile +usano numeri in virgola mobile in doppia precisione per rappresentare i numeri. +Le primissime implementazioni di @command{awk} usavano numeri in virgola mobile in singola precisione. -@item Numero a virgola mobile +@item Numero in virgola mobile Spesso descritto, in termini matematici, come un numero ``razionale'' o reale, @`e soltanto un numero che pu@`o avere una parte frazionaria. Si veda anche ``Doppia precisione'' e ``Singola precisione''. @@ -44875,7 +45457,13 @@ Si veda ``Metacaratteri''. @item Ottale Notazione avente come base 8, nella quale le cifre sono @code{0}--@code{7}. I numeri ottali in C sono scritti premettendo uno @samp{0}, -per indicare la base. Quindi, @code{013} @`e 11 ((1 x 8) + 3). +per indicare la base. +@iftex +Quindi, @code{013} @`e 11 (@math{(1 volta 8) + 3}). +@end iftex +@ifnottex +Quindi, @code{013} @`e 11 ((1 x 8) + 3). +@end ifnottex @xref{Numeri non-decimali}. @item Parentesi Graffe @@ -44894,7 +45482,7 @@ Le parole chiave di @command{gawk} sono: @code{break}, @code{case}, @code{continue}, -@code{default} +@code{default}, @code{delete}, @code{do@dots{}while}, @code{else}, @@ -44954,7 +45542,7 @@ Si veda ``Record in input'' e ``Record in output''. @item Record in input Una singola parte di dati letta da @command{awk}. Solitamente, un -record in input di @command{awk} consiste in una linea di testo. +record in input di @command{awk} consiste in una riga di testo. (@xref{Record}). @item Record in output @@ -45162,7 +45750,7 @@ interi sequenziali compresi in un intervallo prestabilito. @c hence no sectioning command or @node. @display -Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{http://fsf.org/} +Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{https://fsf.org/} This is an unofficial translation of the GNU General Public License into Italian. It was not published by the Free Software Foundation, and does not @@ -45848,7 +46436,7 @@ CORREZIONE. IN NESSUN CASO, A MENO CHE NON SIA RICHIESTO DALLA NORMATIVA VIGENTE O CONCORDATO PER ISCRITTO, I DETENTORI DEL COPYRIGHT, O QUALUNQUE ALTRA PARTE -CHE MODIICA E/O DISTRIBUISCE IL PROGRAMMA SECONDO LE CONDIZIONI PRECEDENTI, +CHE MODIFICA E/O DISTRIBUISCE IL PROGRAMMA SECONDO LE CONDIZIONI PRECEDENTI, POSSONO ESSERE RITENUTI RESPONSABILI NEI CONFRONTI DEL LICENZIATARIO PER DANNI, INCLUSO QUALUNQUE DANNEGGIAMENTO GENERICO, SPECIALE, INCIDENTALE O CONSEQUENZIALE DOVUTO ALL'USO O ALL'IMPOSSIBILIT@`A D'USO DEL PROGRAMMA @@ -45899,8 +46487,8 @@ IDONEIT@`A AD UN PARTICOLARE SCOPO. Si veda la 'GNU General Public License' per ulteriori dettagli. Dovresti aver ricevuto una copia della GNU General Public License assieme a -questo programma; se non @`e cos@`{@dotless{i}}, si veda -@url{http://www.gnu.org/licenses/}. +questo programma; se non @`e cos@`{@dotless{i}}, vedere +@url{https://www.gnu.org/licenses/}. @end smallexample Inoltre, aggiungi le informazioni necessarie a contattarti via posta ordinaria @@ -45927,14 +46515,14 @@ Devi inoltre fare in modo che il tuo datore di lavoro (se lavori come programmatore presso terzi) o la tua scuola, eventualmente, firmino una ``rinuncia al copyright'' sul programma, se necessario. Per maggiori informazioni su questo punto, e su come applicare e rispettare la GNU GPL, -consultare la pagina @url{http://www.gnu.org/licenses/}. +consultare la pagina @url{https://www.gnu.org/licenses/}. La GNU General Public License non consente di incorporare il programma all'interno di software proprietario. Se il tuo programma @`e una libreria di funzioni, potresti ritenere pi@`u opportuno consentire il collegamento tra software proprietario e la tua libreria. Se @`e questo ci@`o che vuoi, allora utilizza la GNU Lesser General Public License anzich@'e questa Licenza, ma prima -leggi @url{http://www.gnu.org/philosophy/why-not-lgpl.html}. +leggi @url{https://www.gnu.org/philosophy/why-not-lgpl.html}. @ifclear FOR_PRINT @c The GNU Free Documentation License. @@ -45957,7 +46545,7 @@ leggi @url{http://www.gnu.org/philosophy/why-not-lgpl.html}. @display Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. -@uref{http://fsf.org} +@uref{https://fsf.org} This is an unofficial translation of the GNU Free Documentation License into Italian. It was not published by the Free Software Foundation, and does not @@ -46395,7 +46983,7 @@ La Free Software Foundation pu@`o occasionalmente pubblicare versioni nuove o rivedute della Licenza per Documentazione Libera GNU. Le nuove versioni saranno simili nello spirito alla versione attuale ma potrebbero differirne in qualche dettaglio per affrontare nuovi problemi e concetti. -Si veda @uref{http://www.gnu.org/copyleft/}. +Si veda @uref{https://www.gnu.org/copyleft/}. Ad ogni versione della licenza viene dato un numero che la distingue. Se il documento specifica che si riferisce ad una versione particolare della @@ -46513,6 +47101,8 @@ Consistency issues: The term "blank" is thus basically reserved for "blank lines" etc. To make dark corners work, the @value{DARKCORNER} has to be outside closing `.' of a sentence and after (pxref{...}). + Make sure that each @value{DARKCORNER} has an index entry, and + also that each `@cindex dark corner' has an @value{DARKCORNER}. " " should have an @w{} around it Use "non-" only with language names or acronyms, or the words bug and option and null Use @command{ftp} when talking about anonymous ftp @@ -46630,5 +47220,7 @@ But to use it you have to say which sorta sucks. TODO: -Check that all dark corners are indexed properly. - +Add a section explaining recursion from ground zero. Probably +easiest to do it with factorial as the example. Explain that +recursion needs a stopping condition. Thanks to +Bill Duncan <bduncan@beachnet.org> for the suggestion. diff --git a/doc/it/texinfo.tex b/doc/it/texinfo.tex index 2a4cdd6c..2ae6710a 100644 --- a/doc/it/texinfo.tex +++ b/doc/it/texinfo.tex @@ -3,11 +3,11 @@ % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % -\def\texinfoversion{2016-02-05.07} +\def\texinfoversion{2018-03-10.14} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, -% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 +% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 % Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or @@ -21,7 +21,7 @@ % General Public License for more details. % % You should have received a copy of the GNU General Public License -% along with this program. If not, see <http://www.gnu.org/licenses/>. +% along with this program. If not, see <https://www.gnu.org/licenses/>. % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without @@ -30,9 +30,9 @@ % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: -% http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or -% http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or -% http://www.gnu.org/software/texinfo/ (the Texinfo home page) +% https://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or +% https://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or +% https://www.gnu.org/software/texinfo/ (the Texinfo home page) % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % @@ -56,7 +56,7 @@ % extent. You can get the existing language-specific files from the % full Texinfo distribution. % -% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. +% The GNU Texinfo home page is https://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} @@ -67,6 +67,10 @@ \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} +% LaTeX's \typeout. This ensures that the messages it is used for +% are identical in format to the corresponding ones from latex/pdflatex. +\def\typeout{\immediate\write17}% + \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. @@ -158,7 +162,7 @@ \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % -% Aggiunto per l'italiano +% added for Italian \gdef\putwordla{la} \gdef\putwordLa{La} \gdef\putwordsivedail{si veda il} @@ -175,6 +179,9 @@ % Give the space character the catcode for a space. \def\spaceisspace{\catcode`\ =10\relax} +% Likewise for ^^M, the end of line character. +\def\endlineisspace{\catcode13=10\relax} + \chardef\dashChar = `\- \chardef\slashChar = `\/ \chardef\underChar = `\_ @@ -324,7 +331,7 @@ % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset -\newdimen\pagewidth \newdimen\pageheight +\newdimen\txipagewidth \newdimen\txipageheight % Main output routine. % @@ -348,7 +355,7 @@ % Common context changes for both heading and footing. % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). - \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars} + \def\commmonheadfootline{\let\hsize=\txipagewidth \texinfochars} % % Retrieve the information for the headings from the marks in the page, % and call Plain TeX's \makeheadline and \makefootline, which use the @@ -447,7 +454,7 @@ \newinsert\margin \dimen\margin=\maxdimen % Main part of page, including any footnotes -\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +\def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) @@ -738,11 +745,11 @@ % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). - \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + \dimen2 = \txipageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 - \ifdim \pagetotal < \vfilllimit\pageheight + \ifdim \pagetotal < \vfilllimit\txipageheight \page \fi \fi @@ -872,36 +879,6 @@ where each line of input produces a line of output.} \temp } -% @| inserts a changebar to the left of the current line. It should -% surround any changed text. This approach does *not* work if the -% change spans more than two lines of output. To handle that, we would -% have adopt a much more difficult approach (putting marks into the main -% vertical list for the beginning and end of each change). This command -% is not documented, not supported, and doesn't work. -% -\def\|{% - % \vadjust can only be used in horizontal mode. - \leavevmode - % - % Append this vertical mode material after the current line in the output. - \vadjust{% - % We want to insert a rule with the height and depth of the current - % leading; that is exactly what \strutbox is supposed to record. - \vskip-\baselineskip - % - % \vadjust-items are inserted at the left edge of the type. So - % the \llap here moves out into the left-hand margin. - \llap{% - % - % For a thicker or thinner bar, change the `1pt'. - \vrule height\baselineskip width1pt - % - % This is the space between the bar and the text. - \hskip 12pt - }% - }% -} - % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} @@ -990,21 +967,14 @@ where each line of input produces a line of output.} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment -% -\def\comment{\begingroup \catcode`\^^M=\active% -\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other\commentxxx}% -{\catcode`\^^M=\active% -\gdef\commentxxx#1^^M{\endgroup% -\futurelet\nexttoken\commentxxxx}% -\gdef\commentxxxx{\ifx\nexttoken\aftermacro\expandafter\comment\fi}% -} \def\c{\begingroup \catcode`\^^M=\active% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \cxxx} {\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}} -% See comment in \scanmacro about why the definitions of @c and @comment differ +% +\let\comment\c % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. @@ -1114,6 +1084,86 @@ where each line of input produces a line of output.} \newif\ifpdf \newif\ifpdfmakepagedest +% +% For LuaTeX +% + +\newif\iftxiuseunicodedestname +\txiuseunicodedestnamefalse % For pdfTeX etc. + +\ifx\luatexversion\thisisundefined +\else + % Use Unicode destination names + \txiuseunicodedestnametrue + % Escape PDF strings with converting UTF-16 from UTF-8 + \begingroup + \catcode`\%=12 + \directlua{ + function UTF16oct(str) + tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377') + for c in string.utfvalues(str) do + if c < 0x10000 then + tex.sprint( + string.format(string.char(0x5c) .. string.char(0x25) .. '03o' .. + string.char(0x5c) .. string.char(0x25) .. '03o', + (c / 256), (c % 256))) + else + c = c - 0x10000 + local c_hi = c / 1024 + 0xd800 + local c_lo = c % 1024 + 0xdc00 + tex.sprint( + string.format(string.char(0x5c) .. string.char(0x25) .. '03o' .. + string.char(0x5c) .. string.char(0x25) .. '03o' .. + string.char(0x5c) .. string.char(0x25) .. '03o' .. + string.char(0x5c) .. string.char(0x25) .. '03o', + (c_hi / 256), (c_hi % 256), + (c_lo / 256), (c_lo % 256))) + end + end + end + } + \endgroup + \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}} + % Escape PDF strings without converting + \begingroup + \directlua{ + function PDFescstr(str) + for c in string.bytes(str) do + if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then + tex.sprint( + string.format(string.char(0x5c) .. string.char(0x25) .. '03o', + c)) + else + tex.sprint(string.char(c)) + end + end + end + } + \endgroup + \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}} + \ifnum\luatexversion>84 + % For LuaTeX >= 0.85 + \def\pdfdest{\pdfextension dest} + \let\pdfoutput\outputmode + \def\pdfliteral{\pdfextension literal} + \def\pdfcatalog{\pdfextension catalog} + \def\pdftexversion{\numexpr\pdffeedback version\relax} + \let\pdfximage\saveimageresource + \let\pdfrefximage\useimageresource + \let\pdflastximage\lastsavedimageresourceindex + \def\pdfendlink{\pdfextension endlink\relax} + \def\pdfoutline{\pdfextension outline} + \def\pdfstartlink{\pdfextension startlink} + \def\pdffontattr{\pdfextension fontattr} + \def\pdfobj{\pdfextension obj} + \def\pdflastobj{\numexpr\pdffeedback lastobj\relax} + \let\pdfpagewidth\pagewidth + \let\pdfpageheight\pageheight + \edef\pdfhorigin{\pdfvariable horigin} + \edef\pdfvorigin{\pdfvariable vorigin} + \fi +\fi + % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as being undefined. \ifx\pdfoutput\thisisundefined @@ -1144,12 +1194,21 @@ where each line of input produces a line of output.} \ifx\pdfescapestring\thisisundefined % No primitive available; should we give a warning or log? % Many times it won't matter. + \xdef#1{#1}% \else % The expandable \pdfescapestring primitive escapes parentheses, % backslashes, and other special chars. \xdef#1{\pdfescapestring{#1}}% \fi } +\def\txiescapepdfutfsixteen#1{% + \ifx\pdfescapestrutfsixteen\thisisundefined + % No UTF-16 converting macro available. + \txiescapepdf{#1}% + \else + \xdef#1{\pdfescapestrutfsixteen{#1}}% + \fi +} \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot @@ -1259,17 +1318,77 @@ output) for that.)} \pdfrefximage \pdflastximage \fi} % - \def\pdfmkdest#1{{% + \def\setpdfdestname#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts - \turnoffactive \makevalueexpandable + \turnoffactive + \iftxiuseunicodedestname + \ifx \declaredencoding \latone + % Pass through Latin-1 characters. + % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode. + \else + \ifx \declaredencoding \utfeight + % Pass through Unicode characters. + \else + % Use ASCII approximations in destination names. + \passthroughcharsfalse + \fi + \fi + \else + % Use ASCII approximations in destination names. + \passthroughcharsfalse + \fi \def\pdfdestname{#1}% \txiescapepdf\pdfdestname - \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % + \def\setpdfoutlinetext#1{{% + \indexnofonts + \makevalueexpandable + \turnoffactive + \ifx \declaredencoding \latone + % The PDF format can use an extended form of Latin-1 in bookmark + % strings. See Appendix D of the PDF Reference, Sixth Edition, for + % the "PDFDocEncoding". + \passthroughcharstrue + % Pass through Latin-1 characters. + % LuaTeX: Convert to Unicode + % pdfTeX: Use Latin-1 as PDFDocEncoding + \def\pdfoutlinetext{#1}% + \else + \ifx \declaredencoding \utfeight + \ifx\luatexversion\thisisundefined + % For pdfTeX with UTF-8. + % TODO: the PDF format can use UTF-16 in bookmark strings, + % but the code for this isn't done yet. + % Use ASCII approximations. + \passthroughcharsfalse + \def\pdfoutlinetext{#1}% + \else + % For LuaTeX with UTF-8. + % Pass through Unicode characters for title texts. + \passthroughcharstrue + \def\pdfoutlinetext{#1}% + \fi + \else + % For non-Latin-1 or non-UTF-8 encodings. + % Use ASCII approximations. + \passthroughcharsfalse + \def\pdfoutlinetext{#1}% + \fi + \fi + % LuaTeX: Convert to UTF-16 + % pdfTeX: Use Latin-1 as PDFDocEncoding + \txiescapepdfutfsixteen\pdfoutlinetext + }} + % + \def\pdfmkdest#1{% + \setpdfdestname{#1}% + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + } + % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % @@ -1297,18 +1416,13 @@ output) for that.)} % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. - \edef\pdfoutlinedest{#3}% - \ifx\pdfoutlinedest\empty - \def\pdfoutlinedest{#4}% - \else - \txiescapepdf\pdfoutlinedest + \setpdfoutlinetext{#1} + \setpdfdestname{#3} + \ifx\pdfdestname\empty + \def\pdfdestname{#4}% \fi % - % Also escape PDF chars in the display string. - \edef\pdfoutlinetext{#1}% - \txiescapepdf\pdfoutlinetext - % - \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% @@ -1464,23 +1578,254 @@ output) for that.)} \fi % \ifx\pdfoutput % -% @image support for XeTeX +% For XeTeX % -\newif\ifxeteximgpdf \ifx\XeTeXrevision\thisisundefined \else % + % XeTeX version check + % + \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1 + % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307. + % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941). + % For avoiding PDF destination name replacement, we use this special + % instead of xdvipdfmx's command line option `-C 0x0010'. + \special{dvipdfmx:config C 0x0010} + % XeTeX 0.99995+ comes with xdvipdfmx 20160307+. + % It can handle Unicode destination names for PDF. + \txiuseunicodedestnametrue + \else + % XeTeX < 0.99996 (TeX Live < 2016) cannot use the + % `dvipdfmx:config' special. + % So for avoiding PDF destination name replacement, + % xdvipdfmx's command line option `-C 0x0010' is necessary. + % + % XeTeX < 0.99995 can not handle Unicode destination names for PDF + % because xdvipdfmx 20150315 has a UTF-16 conversion issue. + % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753). + \txiuseunicodedestnamefalse + \fi + % + % Color support + % + \def\rgbDarkRed{0.50 0.09 0.12} + \def\rgbBlack{0 0 0} + % + \def\pdfsetcolor#1{\special{pdf:scolor [#1]}} + % + % Set color, and create a mark which defines \thiscolor accordingly, + % so that \makeheadline knows which color to restore. + \def\setcolor#1{% + \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% + \domark + \pdfsetcolor{#1}% + } + % + \def\maincolor{\rgbBlack} + \pdfsetcolor{\maincolor} + \edef\thiscolor{\maincolor} + \def\lastcolordefs{} + % + \def\makefootline{% + \baselineskip24pt + \line{\pdfsetcolor{\maincolor}\the\footline}% + } + % + \def\makeheadline{% + \vbox to 0pt{% + \vskip-22.5pt + \line{% + \vbox to8.5pt{}% + % Extract \thiscolor definition from the marks. + \getcolormarks + % Typeset the headline with \maincolor, then restore the color. + \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% + }% + \vss + }% + \nointerlineskip + } + % + % PDF outline support + % + % Emulate pdfTeX primitive + \def\pdfdest name#1 xyz{% + \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}% + } + % + \def\setpdfdestname#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \indexnofonts + \makevalueexpandable + \turnoffactive + \iftxiuseunicodedestname + % Pass through Unicode characters. + \else + % Use ASCII approximations in destination names. + \passthroughcharsfalse + \fi + \def\pdfdestname{#1}% + \txiescapepdf\pdfdestname + }} + % + \def\setpdfoutlinetext#1{{% + \turnoffactive + % Always use Unicode characters in title texts. + \def\pdfoutlinetext{#1}% + % For XeTeX, xdvipdfmx converts to UTF-16. + % So we do not convert. + \txiescapepdf\pdfoutlinetext + }} + % + \def\pdfmkdest#1{% + \setpdfdestname{#1}% + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + } + % + % by default, use black for everything. + \def\urlcolor{\rgbBlack} + \def\linkcolor{\rgbBlack} + \def\endlink{\setcolor{\maincolor}\pdfendlink} + % + \def\dopdfoutline#1#2#3#4{% + \setpdfoutlinetext{#1} + \setpdfdestname{#3} + \ifx\pdfdestname\empty + \def\pdfdestname{#4}% + \fi + % + \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A + << /S /GoTo /D (\pdfdestname) >> >> }% + } + % + \def\pdfmakeoutlines{% + \begingroup + % + % For XeTeX, counts of subentries are not necessary. + % Therefore, we read toc only once. + % + % We use node names as destinations. + \def\partentry##1##2##3##4{}% ignore parts in the outlines + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{1}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{2}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{3}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{4}{##3}{##4}}% + % + \let\appentry\numchapentry% + \let\appsecentry\numsecentry% + \let\appsubsecentry\numsubsecentry% + \let\appsubsubsecentry\numsubsubsecentry% + \let\unnchapentry\numchapentry% + \let\unnsecentry\numsecentry% + \let\unnsubsecentry\numsubsecentry% + \let\unnsubsubsecentry\numsubsubsecentry% + % + % For XeTeX, xdvipdfmx converts strings to UTF-16. + % Therefore, the encoding and the language may not be considered. + % + \indexnofonts + \setupdatafile + % We can have normal brace characters in the PDF outlines, unlike + % Texinfo index files. So set that up. + \def\{{\lbracecharliteral}% + \def\}{\rbracecharliteral}% + \catcode`\\=\active \otherbackslash + \input \tocreadfilename + \endgroup + } + {\catcode`[=1 \catcode`]=2 + \catcode`{=\other \catcode`}=\other + \gdef\lbracecharliteral[{]% + \gdef\rbracecharliteral[}]% + ] + + \special{pdf:docview << /PageMode /UseOutlines >> } + % ``\special{pdf:tounicode ...}'' is not necessary + % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it. + % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315, + % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings. + % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753). +% + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \nextsp} + \def\getfilename#1{% + \filenamelength=0 + % If we don't expand the argument now, \skipspaces will get + % snagged on things like "@value{foo}". + \edef\temp{#1}% + \expandafter\skipspaces\temp|\relax + } + % make a live url in pdf output. + \def\pdfurl#1{% + \begingroup + % it seems we really need yet another set of dummies; have not + % tried to figure out what each command should do in the context + % of @url. for now, just make @/ a no-op, that's the only one + % people have actually reported a problem with. + % + \normalturnoffactive + \def\@{@}% + \let\/=\empty + \makevalueexpandable + % do we want to go so far as to use \indexnofonts instead of just + % special-casing \var here? + \def\var##1{##1}% + % + \leavevmode\setcolor{\urlcolor}% + \special{pdf:bann << /Border [0 0 0] + /Subtype /Link /A << /S /URI /URI (#1) >> >>}% + \endgroup} + \def\endlink{\setcolor{\maincolor}\special{pdf:eann}} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \special{pdf:bann << /Border [0 0 0] + /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}% + \setcolor{\linkcolor}#1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +% + % + % @image support + % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\doxeteximage#1#2#3{% \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % - % XeTeX (and the PDF format) support .pdf, .png, .jpg (among + % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\xeteximgext=\empty - \xeteximgpdffalse \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 @@ -1497,57 +1842,32 @@ output) for that.)} \fi \else \gdef\xeteximgext{png}% \fi - \else \gdef\xeteximgext{PDF} \global\xeteximgpdftrue% + \else \gdef\xeteximgext{PDF}% \fi - \else \gdef\xeteximgext{pdf} \global\xeteximgpdftrue% + \else \gdef\xeteximgext{pdf}% \fi \closein 1 \endgroup % - \ifxeteximgpdf + \def\xetexpdfext{pdf}% + \ifx\xeteximgext\xetexpdfext \XeTeXpdffile "#1".\xeteximgext "" \else - \XeTeXpicfile "#1".\xeteximgext "" + \def\xetexpdfext{PDF}% + \ifx\xeteximgext\xetexpdfext + \XeTeXpdffile "#1".\xeteximgext "" + \else + \XeTeXpicfile "#1".\xeteximgext "" + \fi \fi \ifdim \wd0 >0pt width \xeteximagewidth \fi \ifdim \wd2 >0pt height \xeteximageheight \fi \relax } \fi -\message{fonts,} - -% Change the current font style to #1, remembering it in \curfontstyle. -% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in -% italics, not bold italics. -% -\def\setfontstyle#1{% - \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. - \csname ten#1\endcsname % change the current font -} -% Select #1 fonts with the current style. % -\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} - -\def\rm{\fam=0 \setfontstyle{rm}} -\def\it{\fam=\itfam \setfontstyle{it}} -\def\sl{\fam=\slfam \setfontstyle{sl}} -\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} -\def\tt{\fam=\ttfam \setfontstyle{tt}} - -% Unfortunately, we have to override this for titles and the like, since -% in those cases "rm" is bold. Sigh. -\def\rmisbold{\rm\def\curfontstyle{bf}} - -% Texinfo sort of supports the sans serif font style, which plain TeX does not. -% So we set up a \sf. -\newfam\sffam -\def\sf{\fam=\sffam \setfontstyle{sf}} -\let\li = \sf % Sometimes we call it \li, not \sf. - -% We don't need math for this font style. -\def\ttsl{\setfontstyle{ttsl}} - +\message{fonts,} % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers @@ -1898,8 +2218,8 @@ end \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defsl\slshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} -\def\df{\let\tentt=\deftt \let\tenbf = \defbf -\let\tenttsl=\defttsl \let\tensl=\defsl \bf} +\def\df{\let\ttfont=\deftt \let\bffont = \defbf +\let\ttslfont=\defttsl \let\slfont=\defsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} @@ -1929,6 +2249,20 @@ end \font\smallersy=cmsy8 \def\smallerecsize{0800} +% Fonts for math mode superscripts (7pt). +\def\sevennominalsize{7pt} +\setfont\sevenrm\rmshape{7}{1000}{OT1} +\setfont\seventt\ttshape{10}{700}{OT1TT} +\setfont\sevenbf\bfshape{10}{700}{OT1} +\setfont\sevenit\itshape{7}{1000}{OT1IT} +\setfont\sevensl\slshape{10}{700}{OT1} +\setfont\sevensf\sfshape{10}{700}{OT1} +\setfont\sevensc\scshape{10}{700}{OT1} +\setfont\seventtsl\ttslshape{10}{700}{OT1TT} +\font\seveni=cmmi7 +\font\sevensy=cmsy7 +\def\sevenecsize{0700} + % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} @@ -1986,7 +2320,7 @@ end \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} -% Reduced fonts for @acro in text (10pt). +% Reduced fonts for @acronym in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} @@ -2032,8 +2366,8 @@ end \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defsl\slshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} -\def\df{\let\tentt=\deftt \let\tenbf = \defbf -\let\tensl=\defsl \let\tenttsl=\defttsl \bf} +\def\df{\let\ttfont=\deftt \let\bffont = \defbf +\let\slfont=\defsl \let\ttslfont=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} @@ -2063,6 +2397,20 @@ end \font\smallersy=cmsy8 \def\smallerecsize{0800} +% Fonts for math mode superscripts (7pt). +\def\sevennominalsize{7pt} +\setfont\sevenrm\rmshape{7}{1000}{OT1} +\setfont\seventt\ttshape{10}{700}{OT1TT} +\setfont\sevenbf\bfshape{10}{700}{OT1} +\setfont\sevenit\itshape{7}{1000}{OT1IT} +\setfont\sevensl\slshape{10}{700}{OT1} +\setfont\sevensf\sfshape{10}{700}{OT1} +\setfont\sevensc\scshape{10}{700}{OT1} +\setfont\seventtsl\ttslshape{10}{700}{OT1TT} +\font\seveni=cmmi7 +\font\sevensy=cmsy7 +\def\sevenecsize{0700} + % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} @@ -2119,7 +2467,7 @@ end \font\ssecsy=cmsy10 \def\ssececsize{1000} -% Reduced fonts for @acro in text (9pt). +% Reduced fonts for @acronym in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} @@ -2139,6 +2487,12 @@ end \rm } % end of 10pt text font size definitions, \definetextfontsizex +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000}{OT1} +\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000}{OT1} +\setfont\shortconttt\ttshape{12}{1000}{OT1TT} + % We provide the user-level command % @fonttextsize 10 @@ -2165,20 +2519,57 @@ end \endgroup } +% +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname #1font\endcsname % change the current font +} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + + % In order for the font changes to affect most math symbols and letters, -% we have to define the \textfont of the standard families. We don't -% bother to reset \scriptfont and \scriptscriptfont; awaiting user need. +% we have to define the \textfont of the standard families. +% We don't bother to reset \scriptscriptfont; awaiting user need. % \def\resetmathfonts{% - \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy - \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf - \textfont\ttfam=\tentt \textfont\sffam=\tensf + \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont + \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont + \textfont\ttfam=\ttfont \textfont\sffam=\sffont + % + % Fonts for superscript. Note that the 7pt fonts are used regardless + % of the current font size. + \scriptfont0=\sevenrm \scriptfont1=\seveni \scriptfont2=\sevensy + \scriptfont\itfam=\sevenit \scriptfont\slfam=\sevensl + \scriptfont\bffam=\sevenbf \scriptfont\ttfam=\seventt + \scriptfont\sffam=\sevensf } -% The font-changing commands redefine the meanings of \tenSTYLE, instead -% of just \STYLE. We do this because \STYLE needs to also set the -% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire -% \tenSTYLE to set the current font. +% + +% The font-changing commands (all called \...fonts) redefine the meanings +% of \STYLEfont, instead of just \STYLE. We do this because \STYLE needs +% to also set the current \fam for math mode. Our \STYLE (e.g., \rm) +% commands hardwire \STYLEfont to set the current font. +% +% The fonts used for \ifont are for "math italics" (\itfont is for italics +% in regular text). \syfont is also used in math mode only. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used @@ -2186,78 +2577,63 @@ end % % This all needs generalizing, badly. % -\def\textfonts{% - \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl - \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc - \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy - \let\tenttsl=\textttsl - \def\curfontsize{text}% - \def\lsize{reduced}\def\lllsize{smaller}% - \resetmathfonts \setleading{\textleading}} -\def\titlefonts{% - \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl - \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc - \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy - \let\tenttsl=\titlettsl - \def\curfontsize{title}% - \def\lsize{chap}\def\lllsize{subsec}% - \resetmathfonts \setleading{27pt}} -\def\titlefont#1{{\titlefonts\rmisbold #1}} -\def\chapfonts{% - \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl - \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc - \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy - \let\tenttsl=\chapttsl - \def\curfontsize{chap}% - \def\lsize{sec}\def\lllsize{text}% - \resetmathfonts \setleading{19pt}} -\def\secfonts{% - \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl - \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc - \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy - \let\tenttsl=\secttsl - \def\curfontsize{sec}% - \def\lsize{subsec}\def\lllsize{reduced}% - \resetmathfonts \setleading{17pt}} -\def\subsecfonts{% - \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl - \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc - \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy - \let\tenttsl=\ssecttsl - \def\curfontsize{ssec}% - \def\lsize{text}\def\lllsize{small}% - \resetmathfonts \setleading{15pt}} -\let\subsubsecfonts = \subsecfonts -\def\reducedfonts{% - \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl - \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc - \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy - \let\tenttsl=\reducedttsl - \def\curfontsize{reduced}% - \def\lsize{small}\def\lllsize{smaller}% - \resetmathfonts \setleading{10.5pt}} -\def\smallfonts{% - \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl - \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc - \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy - \let\tenttsl=\smallttsl - \def\curfontsize{small}% - \def\lsize{smaller}\def\lllsize{smaller}% - \resetmathfonts \setleading{10.5pt}} -\def\smallerfonts{% - \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl - \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc - \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy - \let\tenttsl=\smallerttsl - \def\curfontsize{smaller}% - \def\lsize{smaller}\def\lllsize{smaller}% - \resetmathfonts \setleading{9.5pt}} -% Fonts for short table of contents. -\setfont\shortcontrm\rmshape{12}{1000}{OT1} -\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 -\setfont\shortcontsl\slshape{12}{1000}{OT1} -\setfont\shortconttt\ttshape{12}{1000}{OT1TT} +\def\assignfonts#1{% + \expandafter\let\expandafter\rmfont\csname #1rm\endcsname + \expandafter\let\expandafter\itfont\csname #1it\endcsname + \expandafter\let\expandafter\slfont\csname #1sl\endcsname + \expandafter\let\expandafter\bffont\csname #1bf\endcsname + \expandafter\let\expandafter\ttfont\csname #1tt\endcsname + \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname + \expandafter\let\expandafter\sffont \csname #1sf\endcsname + \expandafter\let\expandafter\ifont \csname #1i\endcsname + \expandafter\let\expandafter\syfont \csname #1sy\endcsname + \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname +} + +\newif\ifrmisbold + +% Select smaller font size with the current style. Used to change font size +% in, e.g., the LaTeX logo and acronyms. If we are using bold fonts for +% normal roman text, also use bold fonts for roman text in the smaller size. +\def\switchtolllsize{% + \expandafter\assignfonts\expandafter{\lllsize}% + \ifrmisbold + \let\rmfont\bffont + \fi + \csname\curfontstyle\endcsname +}% + +\def\switchtolsize{% + \expandafter\assignfonts\expandafter{\lsize}% + \ifrmisbold + \let\rmfont\bffont + \fi + \csname\curfontstyle\endcsname +}% + +\def\definefontsetatsize#1#2#3#4#5{% +\expandafter\def\csname #1fonts\endcsname{% + \def\curfontsize{#1}% + \def\lsize{#2}\def\lllsize{#3}% + \csname rmisbold#5\endcsname + \assignfonts{#1}% + \resetmathfonts + \setleading{#4}% +}} + +\definefontsetatsize{text} {reduced}{smaller}{\textleading}{false} +\definefontsetatsize{title} {chap} {subsec} {27pt} {true} +\definefontsetatsize{chap} {sec} {text} {19pt} {true} +\definefontsetatsize{sec} {subsec} {reduced}{17pt} {true} +\definefontsetatsize{ssec} {text} {small} {15pt} {true} +\definefontsetatsize{reduced}{small} {smaller}{10.5pt}{false} +\definefontsetatsize{small} {smaller}{smaller}{10.5pt}{false} +\definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false} + +\def\titlefont#1{{\titlefonts\rm #1}} +\let\subsecfonts = \ssecfonts +\let\subsubsecfonts = \ssecfonts % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} @@ -2295,26 +2671,11 @@ end % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost -% style and the set of \ifmarkupSTYLE switches for all styles -% currently in effect. -\newif\ifmarkupvar -\newif\ifmarkupsamp -\newif\ifmarkupkey -%\newif\ifmarkupfile % @file == @samp. -%\newif\ifmarkupoption % @option == @samp. -\newif\ifmarkupcode -\newif\ifmarkupkbd -%\newif\ifmarkupenv % @env == @code. -%\newif\ifmarkupcommand % @command == @code. -\newif\ifmarkuptex % @tex (and part of @math, for now). -\newif\ifmarkupexample -\newif\ifmarkupverb -\newif\ifmarkupverbatim +% style. \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% - \csname markup#1true\endcsname \def\currentmarkupstyle{#1}% \markupstylesetup } @@ -2376,11 +2737,15 @@ end % lilypond developers report. xpdf does work with the regular 0x27. % \def\codequoteright{% - \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax - \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax - '% + \ifmonospace + \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax + \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax + '% + \else \char'15 \fi \else \char'15 \fi - \else \char'15 \fi + \else + '% + \fi } % % and a similar option for the left quote char vs. a grave accent. @@ -2388,13 +2753,17 @@ end % the code environments to do likewise. % \def\codequoteleft{% - \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax - \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax - % [Knuth] pp. 380,381,391 - % \relax disables Spanish ligatures ?` and !` of \tt font. - \relax`% + \ifmonospace + \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax + \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax + % [Knuth] pp. 380,381,391 + % \relax disables Spanish ligatures ?` and !` of \tt font. + \relax`% + \else \char'22 \fi \else \char'22 \fi - \else \char'22 \fi + \else + \relax`% + \fi } % Commands to set the quote options. @@ -2673,6 +3042,7 @@ end \setbox0 = \hbox{\ignorespaces #2}% look for second arg \ifdim\wd0 > 0pt \ifpdf + % For pdfTeX and LuaTeX \ifurefurlonlylink % PDF plus option to not display url, show just arg \unhbox0 @@ -2682,7 +3052,19 @@ end \unhbox0\ (\urefcode{#1})% \fi \else - \unhbox0\ (\urefcode{#1})% DVI, always show arg and url + \ifx\XeTeXrevision\thisisundefined + \unhbox0\ (\urefcode{#1})% DVI, always show arg and url + \else + % For XeTeX + \ifurefurlonlylink + % PDF plus option to not display url, show just arg + \unhbox0 + \else + % PDF, normally display both arg and url for consistency, + % visibility, if the pdf is eventually used to print, etc. + \unhbox0\ (\urefcode{#1})% + \fi + \fi \fi \else \urefcode{#1}% only url given, so show it @@ -2783,7 +3165,18 @@ end \endlink \endgroup} \else - \let\email=\uref + \ifx\XeTeXrevision\thisisundefined + \let\email=\uref + \else + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} + \fi \fi % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), @@ -2858,7 +3251,7 @@ end % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% - {\selectfonts\lsize #1}% + {\switchtolsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% @@ -2951,10 +3344,10 @@ end % fix it (significant additions to font machinery) until someone notices. % \def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi} -\def\finishsub#1{$\sb{\hbox{\selectfonts\lllsize #1}}$}% +\def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}% % \def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi} -\def\finishsup#1{$\ptexsp{\hbox{\selectfonts\lllsize #1}}$}% +\def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}% % @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. % Ignore unless FMTNAME == tex; then it is like @iftex and @tex, @@ -3018,23 +3411,10 @@ end \let\atchar=\@ % @{ @} @lbracechar{} @rbracechar{} all generate brace characters. -% Unless we're in typewriter, use \ecfont because the CM text fonts do -% not have braces, and we don't want to switch into math. -\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}} -\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}} -\let\{=\mylbrace \let\lbracechar=\{ -\let\}=\myrbrace \let\rbracechar=\} -\begingroup - % Definitions to produce \{ and \} commands for indices, - % and @{ and @} for the aux/toc files. - \catcode`\{ = \other \catcode`\} = \other - \catcode`\[ = 1 \catcode`\] = 2 - \catcode`\! = 0 \catcode`\\ = \other - !gdef!lbracecmd[\{]% - !gdef!rbracecmd[\}]% - !gdef!lbraceatcmd[@{]% - !gdef!rbraceatcmd[@}]% -!endgroup +\def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}} +\def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}} +\let\{=\lbracechar +\let\}=\rbracechar % @comma{} to avoid , parsing problems. \let\comma = , @@ -3052,8 +3432,8 @@ end % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} -\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} -\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} +\def\ordf{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} @@ -3082,12 +3462,12 @@ end {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{% \ifx\textnominalsize\xwordpt - % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX. + % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX. % Revert to plain's \scriptsize, which is 7pt. \count255=\the\fam $\fam\count255 \scriptstyle A$% \else % For 11pt, we can use our lllsize. - \selectfonts\lllsize A% + \switchtolllsize A% \fi }% \vss @@ -3153,7 +3533,7 @@ end % \newbox\errorbox % -{\tentt \global\dimen0 = 3em}% Width of the box. +{\ttfont \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt} @@ -3304,7 +3684,7 @@ end % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% - $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + $^{{\ooalign{\hfil\raise.07ex\hbox{\switchtolllsize R}% \hfil\crcr\Orb}}% }$% } @@ -3337,13 +3717,16 @@ end \newif\ifseenauthor \newif\iffinishedtitlepage -% Do an implicit @contents or @shortcontents after @end titlepage if the -% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. -% -\newif\ifsetcontentsaftertitlepage - \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue -\newif\ifsetshortcontentsaftertitlepage - \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue +% @setcontentsaftertitlepage used to do an implicit @contents or +% @shortcontents after @end titlepage, but it is now obsolete. +\def\setcontentsaftertitlepage{% + \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo + command; move your @contents command if you want the contents + after the title page.}}% +\def\setshortcontentsaftertitlepage{% + \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo + command; move your @shortcontents and @contents commands if you + want the contents after the title page.}}% \parseargdef\shorttitlepage{% \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% @@ -3385,20 +3768,6 @@ end % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon - % - % If they want short, they certainly want long too. - \ifsetshortcontentsaftertitlepage - \shortcontents - \contents - \global\let\shortcontents = \relax - \global\let\contents = \relax - \fi - % - \ifsetcontentsaftertitlepage - \contents - \global\let\contents = \relax - \global\let\shortcontents = \relax - \fi } \def\finishtitlepage{% @@ -3409,12 +3778,11 @@ end % Settings used for typesetting titles: no hyphenation, no indentation, % don't worry much about spacing, ragged right. This should be used -% inside a \vbox, and fonts need to be set appropriately first. Because -% it is always used for titles, nothing else, we call \rmisbold. \par -% should be specified before the end of the \vbox, since a vbox is a group. +% inside a \vbox, and fonts need to be set appropriately first. \par should +% be specified before the end of the \vbox, since a vbox is a group. % \def\raggedtitlesettings{% - \rmisbold + \rm \hyphenpenalty=10000 \parindent=0pt \tolerance=5000 @@ -3423,7 +3791,7 @@ end % Macros to be used within @titlepage: -\let\subtitlerm=\tenrm +\let\subtitlerm=\rmfont \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% @@ -3449,7 +3817,7 @@ end \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi - {\secfonts\rmisbold \leftline{#1}}% + {\secfonts\rm \leftline{#1}}% \fi } @@ -3502,7 +3870,7 @@ end % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. - \global\advance\pageheight by -12pt + \global\advance\txipageheight by -12pt \global\advance\vsize by -12pt } @@ -3527,9 +3895,9 @@ end \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} -\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} +\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } -\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} +\parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% @@ -3550,7 +3918,7 @@ end % By default, they are off at the start of a document, % and turned `on' after @end titlepage. -\def\headings #1 {\csname HEADINGS#1\endcsname} +\parseargdef\headings{\csname HEADINGS#1\endcsname} \def\headingsoff{% non-global headings elimination \evenheadline={\hfil}\evenfootline={\hfil}% @@ -4364,6 +4732,31 @@ end \fi } +% Like \expandablevalue, but completely expandable (the \message in the +% definition above operates at the execution level of TeX). Used when +% writing to auxiliary files, due to the expansion that \write does. +% If flag is undefined, pass through an unexpanded @value command: maybe it +% will be set by the time it is read back in. +% +% NB flag names containing - or _ may not work here. +\def\dummyvalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \noexpand\value{#1}% + \else + \csname SET#1\endcsname + \fi +} + +% Used for @value's in index entries to form the sort key: expand the @value +% if possible, otherwise sort late. +\def\indexnofontsvalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + ZZZZZZZ + \else + \csname SET#1\endcsname + \fi +} + % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % @@ -4488,14 +4881,7 @@ end % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% - % Only do \closeout if we haven't already done it, else we'll end up - % closing the target index. - \expandafter \ifx\csname donesynindex#2\endcsname \relax - % The \closeout helps reduce unnecessary open files; the limit on the - % Acorn RISC OS is a mere 16 files. - \expandafter\closeout\csname#2indfile\endcsname - \expandafter\let\csname donesynindex#2\endcsname = 1 - \fi + \requireopenindexfile{#3}% % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp @@ -4505,7 +4891,7 @@ end % Define \doindex, the driver for all index macros. % Argument #1 is generated by the calling \fooindex macro, -% and it the two-letter name of the index. +% and it is the two-letter name of the index. \def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx} \def\doindexxxx #1{\doind{\indexname}{#1}} @@ -4514,63 +4900,61 @@ end \def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx} \def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}} -% Used when writing an index entry out to an index file, to prevent + +% Used when writing an index entry out to an index file to prevent % expansion of Texinfo commands that can appear in an index entry. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. - \def\@{@}% change to @@ when we switch to @ as escape char in index files. - \def\ {\realbackslash\space }% - % - % Need these unexpandable (because we define \tt as a dummy) - % definitions when @{ or @} appear in index entry text. Also, more - % complicated, when \tex is in effect and \{ is a \delimiter again. - % We can't use \lbracecmd and \rbracecmd because texindex assumes - % braces and backslashes are used only as delimiters. Perhaps we - % should use @lbracechar and @rbracechar? - \def\{{{\tt\char123}}% - \def\}{{\tt\char125}}% + \definedummyletter\@% + \definedummyletter\ % + % + % For texindex which always views { and } as separators. + \def\{{\lbracechar{}}% + \def\}{\rbracechar{}}% % % Do the redefinitions. - \commondummies + \definedummies } -% For the aux and toc files, @ is the escape character. So we want to -% redefine everything using @ as the escape character (instead of -% \realbackslash, still used for index files). When everything uses @, -% this will be simpler. +% Used for the aux and toc files, where @ is the escape character. % \def\atdummies{% - \def\@{@@}% - \def\ {@ }% - \let\{ = \lbraceatcmd - \let\} = \rbraceatcmd + \definedummyletter\@% + \definedummyletter\ % + \definedummyletter\{% + \definedummyletter\}% % % Do the redefinitions. - \commondummies + \definedummies \otherbackslash } -% Called from \indexdummies and \atdummies. +% \definedummyword defines \#1 as \string\#1\space, thus effectively +% preventing its expansion. This is used only for control words, +% not control letters, because the \space would be incorrect for +% control characters, but is needed to separate the control word +% from whatever follows. % -\def\commondummies{% - % \definedummyword defines \#1 as \string\#1\space, thus effectively - % preventing its expansion. This is used only for control words, - % not control letters, because the \space would be incorrect for - % control characters, but is needed to separate the control word - % from whatever follows. - % - % For control letters, we have \definedummyletter, which omits the - % space. - % - % These can be used both for control words that take an argument and - % those that do not. If it is followed by {arg} in the input, then - % that will dutifully get written to the index (or wherever). - % - \def\definedummyword ##1{\def##1{\string##1\space}}% - \def\definedummyletter##1{\def##1{\string##1}}% - \let\definedummyaccent\definedummyletter +% These can be used both for control words that take an argument and +% those that do not. If it is followed by {arg} in the input, then +% that will dutifully get written to the index (or wherever). +% +% For control letters, we have \definedummyletter, which omits the +% space. +% +\def\definedummyword #1{\def#1{\string#1\space}}% +\def\definedummyletter#1{\def#1{\string#1}}% +\let\definedummyaccent\definedummyletter + +% Called from \indexdummies and \atdummies, to effectively prevent +% the expansion of commands. +% +\def\definedummies{% % + \let\commondummyword\definedummyword + \let\commondummyletter\definedummyletter + \let\commondummyaccent\definedummyaccent \commondummiesnofonts % \definedummyletter\_% @@ -4611,6 +4995,7 @@ end \definedummyword\TeX % % Assorted special characters. + \definedummyword\atchar \definedummyword\arrow \definedummyword\bullet \definedummyword\comma @@ -4650,85 +5035,82 @@ end % % We want to disable all macros so that they are not expanded by \write. \macrolist + \let\value\dummyvalue % \normalturnoffactive - % - % Handle some cases of @value -- where it does not contain any - % (non-fully-expandable) commands. - \makevalueexpandable } -% \commondummiesnofonts: common to \commondummies and \indexnofonts. -% Define \definedumyletter, \definedummyaccent and \definedummyword before -% using. +% \commondummiesnofonts: common to \definedummies and \indexnofonts. +% Define \commondummyletter, \commondummyaccent and \commondummyword before +% using. Used for accents, font commands, and various control letters. % \def\commondummiesnofonts{% % Control letters and accents. - \definedummyletter\!% - \definedummyaccent\"% - \definedummyaccent\'% - \definedummyletter\*% - \definedummyaccent\,% - \definedummyletter\.% - \definedummyletter\/% - \definedummyletter\:% - \definedummyaccent\=% - \definedummyletter\?% - \definedummyaccent\^% - \definedummyaccent\`% - \definedummyaccent\~% - \definedummyword\u - \definedummyword\v - \definedummyword\H - \definedummyword\dotaccent - \definedummyword\ogonek - \definedummyword\ringaccent - \definedummyword\tieaccent - \definedummyword\ubaraccent - \definedummyword\udotaccent - \definedummyword\dotless + \commondummyletter\!% + \commondummyaccent\"% + \commondummyaccent\'% + \commondummyletter\*% + \commondummyaccent\,% + \commondummyletter\.% + \commondummyletter\/% + \commondummyletter\:% + \commondummyaccent\=% + \commondummyletter\?% + \commondummyaccent\^% + \commondummyaccent\`% + \commondummyaccent\~% + \commondummyword\u + \commondummyword\v + \commondummyword\H + \commondummyword\dotaccent + \commondummyword\ogonek + \commondummyword\ringaccent + \commondummyword\tieaccent + \commondummyword\ubaraccent + \commondummyword\udotaccent + \commondummyword\dotless % % Texinfo font commands. - \definedummyword\b - \definedummyword\i - \definedummyword\r - \definedummyword\sansserif - \definedummyword\sc - \definedummyword\slanted - \definedummyword\t + \commondummyword\b + \commondummyword\i + \commondummyword\r + \commondummyword\sansserif + \commondummyword\sc + \commondummyword\slanted + \commondummyword\t % % Commands that take arguments. - \definedummyword\abbr - \definedummyword\acronym - \definedummyword\anchor - \definedummyword\cite - \definedummyword\code - \definedummyword\command - \definedummyword\dfn - \definedummyword\dmn - \definedummyword\email - \definedummyword\emph - \definedummyword\env - \definedummyword\file - \definedummyword\image - \definedummyword\indicateurl - \definedummyword\inforef - \definedummyword\kbd - \definedummyword\key - \definedummyword\math - \definedummyword\option - \definedummyword\pxref - \definedummyword\ref - \definedummyword\samp - \definedummyword\strong - \definedummyword\tie - \definedummyword\U - \definedummyword\uref - \definedummyword\url - \definedummyword\var - \definedummyword\verb - \definedummyword\w - \definedummyword\xref + \commondummyword\abbr + \commondummyword\acronym + \commondummyword\anchor + \commondummyword\cite + \commondummyword\code + \commondummyword\command + \commondummyword\dfn + \commondummyword\dmn + \commondummyword\email + \commondummyword\emph + \commondummyword\env + \commondummyword\file + \commondummyword\image + \commondummyword\indicateurl + \commondummyword\inforef + \commondummyword\kbd + \commondummyword\key + \commondummyword\math + \commondummyword\option + \commondummyword\pxref + \commondummyword\ref + \commondummyword\samp + \commondummyword\strong + \commondummyword\tie + \commondummyword\U + \commondummyword\uref + \commondummyword\url + \commondummyword\var + \commondummyword\verb + \commondummyword\w + \commondummyword\xref } % For testing: output @{ and @} in index sort strings as \{ and \}. @@ -4784,11 +5166,11 @@ end % \def\indexnofonts{% % Accent commands should become @asis. - \def\definedummyaccent##1{\let##1\asis}% + \def\commondummyaccent##1{\let##1\asis}% % We can just ignore other control letters. - \def\definedummyletter##1{\let##1\empty}% + \def\commondummyletter##1{\let##1\empty}% % All control words become @asis by default; overrides below. - \let\definedummyword\definedummyaccent + \let\commondummyword\commondummyaccent \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command @@ -4830,37 +5212,40 @@ end \def\LaTeX{LaTeX}% \def\TeX{TeX}% % - % Assorted special characters. - % (The following {} will end up in the sort string, but that's ok.) - \def\arrow{->}% - \def\bullet{bullet}% - \def\comma{,}% - \def\copyright{copyright}% - \def\dots{...}% - \def\enddots{...}% - \def\equiv{==}% - \def\error{error}% - \def\euro{euro}% - \def\expansion{==>}% - \def\geq{>=}% - \def\guillemetleft{<<}% - \def\guillemetright{>>}% - \def\guilsinglleft{<}% - \def\guilsinglright{>}% - \def\leq{<=}% - \def\minus{-}% - \def\point{.}% - \def\pounds{pounds}% - \def\print{-|}% - \def\quotedblbase{"}% - \def\quotedblleft{"}% - \def\quotedblright{"}% - \def\quoteleft{`}% - \def\quoteright{'}% - \def\quotesinglbase{,}% - \def\registeredsymbol{R}% - \def\result{=>}% - \def\textdegree{o}% + % Assorted special characters. \defglyph gives the control sequence a + % definition that removes the {} that follows its use. + \defglyph\atchar{@}% + \defglyph\arrow{->}% + \defglyph\bullet{bullet}% + \defglyph\comma{,}% + \defglyph\copyright{copyright}% + \defglyph\dots{...}% + \defglyph\enddots{...}% + \defglyph\equiv{==}% + \defglyph\error{error}% + \defglyph\euro{euro}% + \defglyph\expansion{==>}% + \defglyph\geq{>=}% + \defglyph\guillemetleft{<<}% + \defglyph\guillemetright{>>}% + \defglyph\guilsinglleft{<}% + \defglyph\guilsinglright{>}% + \defglyph\leq{<=}% + \defglyph\lbracechar{\{}% + \defglyph\minus{-}% + \defglyph\point{.}% + \defglyph\pounds{pounds}% + \defglyph\print{-|}% + \defglyph\quotedblbase{"}% + \defglyph\quotedblleft{"}% + \defglyph\quotedblright{"}% + \defglyph\quoteleft{`}% + \defglyph\quoteright{'}% + \defglyph\quotesinglbase{,}% + \defglyph\rbracechar{\}}% + \defglyph\registeredsymbol{R}% + \defglyph\result{=>}% + \defglyph\textdegree{o}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. @@ -4873,7 +5258,11 @@ end % goes to end-of-line is not handled. % \macrolist + \let\value\indexnofontsvalue } +\def\defglyph#1#2{\def#1##1{#2}} % see above + + \let\SETmarginindex=\relax % put index entries in margin (undocumented)? @@ -4920,9 +5309,10 @@ end \ifx\suffix\indexisfl\def\suffix{f1}\fi % Open the file \immediate\openout\csname#1indfile\endcsname \jobname.\suffix - % Using \immediate here prevents an object entering into the current box, - % which could confound checks such as those in \safewhatsit for preceding - % skips. + % Using \immediate above here prevents an object entering into the current + % box, which could confound checks such as those in \safewhatsit for + % preceding skips. + \typeout{Writing index file \jobname.\suffix}% \fi} \def\indexisfl{fl} @@ -5120,7 +5510,7 @@ end % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). - \catcode`\@ = 11 + \catcode`\@ = 12 % See comment in \requireopenindexfile. \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi \openin 1 \jobname.\indexname s @@ -5130,9 +5520,9 @@ end % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent + \typeout{No file \jobname.\indexname s.}% \else \catcode`\\ = 0 - \escapechar = `\\ % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so @@ -5148,17 +5538,15 @@ end \let\indexlbrace\{ % Likewise, set these sequences for braces \let\indexrbrace\} % used in the sort key. \begindoublecolumns - \let\entryorphanpenalty=\indexorphanpenalty + \let\dotheinsertentrybox\dotheinsertentryboxwithpenalty % % Read input from the index file line by line. \loopdo - \ifeof1 - \let\firsttoken\relax - \else + \ifeof1 \else \read 1 to \nextline - \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}% - \act \fi + % + \indexinputprocessing \thisline % \ifeof1\else @@ -5170,12 +5558,20 @@ end \fi \closein 1 \endgroup} +\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx} +\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next} +\def\indexinputprocessing{% + \ifeof1 + \let\firsttoken\relax + \else + \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}% + \act + \fi +} \def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken} \long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1} -\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx} -\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. @@ -5249,6 +5645,12 @@ end \def\entry{% \begingroup % + % For pdfTeX and XeTeX. + % The redefinition of \domark stops marks being added in \pdflink to + % preserve coloured links across page boundaries. Otherwise the marks + % would get in the way of \lastbox in \insertentrybox. + \let\domark\relax + % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par @@ -5262,10 +5664,6 @@ end \def\*{\unskip\space\ignorespaces}% \def\entrybreak{\hfil\break}% An undocumented command % - % A bit of stretch before each entry for the benefit of balancing - % columns. - \vskip 0pt plus0.5pt - % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = @@ -5299,26 +5697,25 @@ end % \ifpdf \pdfgettoks#1.% - \bgroup\let\domark\relax - \hskip\skip\thinshrinkable\the\toksA - \egroup - % The redefinion of \domark stops marks being added in \pdflink to - % preserve coloured links across page boundaries. Otherwise the marks - % would get in the way of \lastbox in \insertindexentrybox. + \hskip\skip\thinshrinkable\the\toksA \else - \hskip\skip\thinshrinkable #1% + \ifx\XeTeXrevision\thisisundefined + \hskip\skip\thinshrinkable #1% + \else + \pdfgettoks#1.% + \hskip\skip\thinshrinkable\the\toksA + \fi \fi \fi \egroup % end \boxA \ifdim\wd\boxB = 0pt - \global\setbox\entryindexbox=\vbox{\unhbox\boxA}% + \global\setbox\entrybox=\vbox{\unhbox\boxA}% \else - \global\setbox\entryindexbox=\vbox\bgroup - \prevdepth=\entrylinedepth - \noindent + \global\setbox\entrybox=\vbox\bgroup % We want the text of the entries to be aligned to the left, and the % page numbers to be aligned to the right. % + \parindent = 0pt \advance\leftskip by 0pt plus 1fil \advance\leftskip by 0pt plus -1fill \rightskip = 0pt plus -1fil @@ -5327,8 +5724,6 @@ end % if the list of page numbers is long, to be aligned to the right. \parfillskip=0pt plus -1fill % - \hangindent=1em - % \advance\rightskip by \entryrightmargin % Determine how far we can stretch into the margin. % This allows, e.g., "Appendix H GNU Free Documentation License" to @@ -5346,19 +5741,27 @@ end \advance\dimen@ii by 1\dimen@i \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line \ifdim\dimen@ > 0.8\dimen@ii % due to long index text - \dimen@ = 0.7\dimen@ % Try to split the text roughly evenly + % Try to split the text roughly evenly. \dimen@ will be the length of + % the first line. + \dimen@ = 0.7\dimen@ \dimen@ii = \hsize - \advance \dimen@ii by -1em \ifnum\dimen@>\dimen@ii - % If the entry is too long, use the whole line + % If the entry is too long (for example, if it needs more than + % two lines), use all the space in the first line. \dimen@ = \dimen@ii \fi \advance\leftskip by 0pt plus 1fill % ragged right \advance \dimen@ by 1\rightskip - \parshape = 2 0pt \dimen@ 1em \dimen@ii - % Ideally we'd add a finite glue at the end of the first line only, but - % TeX doesn't seem to provide a way to do such a thing. + \parshape = 2 0pt \dimen@ 0em \dimen@ii + % Ideally we'd add a finite glue at the end of the first line only, + % instead of using \parshape with explicit line lengths, but TeX + % doesn't seem to provide a way to do such a thing. + % + % Indent all lines but the first one. + \advance\leftskip by 1em + \advance\parindent by -1em \fi\fi + \indent % start paragraph \unhbox\boxA % % Do not prefer a separate line ending with a hyphen to fewer lines. @@ -5374,53 +5777,54 @@ end \egroup % The \vbox \fi \endgroup - % delay text of entry until after penalty - \bgroup\aftergroup\insertindexentrybox - \entryorphanpenalty + \dotheinsertentrybox }} \newskip\thinshrinkable \skip\thinshrinkable=.15em minus .15em -\newbox\entryindexbox -\def\insertindexentrybox{% - \copy\entryindexbox - % The following gets the depth of the last box. This is for even - % line spacing when entries span several lines. - \setbox\dummybox\vbox{% - \unvbox\entryindexbox - \nointerlineskip - \lastbox - \global\entrylinedepth=\prevdepth - }% - % Note that we couldn't simply \unvbox\entryindexbox followed by - % \nointerlineskip\lastbox to remove the last box and then reinstate it, - % because this resets how far the box has been \moveleft'ed to 0. \unvbox - % doesn't affect \prevdepth either. +\newbox\entrybox +\def\insertentrybox{% + \ourunvbox\entrybox } -\newdimen\entrylinedepth -% Default is no penalty -\let\entryorphanpenalty\egroup +% default definition +\let\dotheinsertentrybox\insertentrybox + +% Use \lastbox to take apart vbox box by box, and add each sub-box +% to the current vertical list. +\def\ourunvbox#1{% +\bgroup % for local binding of \delayedbox + % Remove the last box from box #1 + \global\setbox#1=\vbox{% + \unvbox#1% + \unskip % remove any glue + \unpenalty + \global\setbox\interbox=\lastbox + }% + \setbox\delayedbox=\box\interbox + \ifdim\ht#1=0pt\else + \ourunvbox#1 % Repeat on what's left of the box + \nobreak + \fi + \box\delayedbox +\egroup +} +\newbox\delayedbox +\newbox\interbox % Used from \printindex. \firsttoken should be the first token % after the \entry. If it's not another \entry, we are at the last % line of a group of index entries, so insert a penalty to discourage -% orphaned index entries. -\long\def\indexorphanpenalty{% - \def\isentry{\entry}% +% widowed index entries. +\def\dotheinsertentryboxwithpenalty{% \ifx\firsttoken\isentry \else - \unskip\penalty 9000 - % The \unskip here stops breaking before the glue. It relies on the - % \vskip above being there, otherwise there is an error - % "You can't use `\unskip' in vertical mode". There has to be glue - % in the current vertical list that hasn't been added to the - % "current page". See Chapter 24 of the TeXbook. This contradicts - % Section 8.3.7 in "TeX by Topic," though. + \penalty 9000 \fi - \egroup % now comes the box added with \aftergroup + \insertentrybox } +\def\isentry{\entry}% % Like plain.tex's \dotfill, except uses up at least 1 em. % The filll stretch here overpowers both the fil and fill stretch to push @@ -5441,7 +5845,11 @@ end \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else - #2 + \ifx\XeTeXrevision\thisisundefined + #2 + \else + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \fi \fi \par }} @@ -5453,8 +5861,6 @@ end \newbox\partialpage \newdimen\doublecolumnhsize -\newdimen\doublecolumntopgap -\doublecolumntopgap = 0pt % Use inside an output routine to save \topmark and \firstmark \def\savemarks{% @@ -5535,14 +5941,12 @@ end \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % - % Double the \vsize as well. (We don't need a separate register here, - % since nobody clobbers \vsize.) - \global\doublecolumntopgap = \topskip - \global\advance\doublecolumntopgap by -1\baselineskip - \advance\vsize by -1\doublecolumntopgap + % Double the \vsize as well. + \advance\vsize by -\ht\partialpage \vsize = 2\vsize - \topskip=0pt - \global\entrylinedepth=0pt\relax + % + % For the benefit of balancing columns + \advance\baselineskip by 0pt plus 0.5pt } % The double-column output routine for all double-column pages except @@ -5556,12 +5960,12 @@ end % previous page. \dimen@ = \vsize \divide\dimen@ by 2 - \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. - \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@ + \global\advance\vsize by 2\ht\partialpage \onepageout\pagesofar - \unvbox255 + \unvbox\PAGE \penalty\outputpenalty } % @@ -5572,9 +5976,7 @@ end % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize - \vbox{% - \vskip\doublecolumntopgap - \hbox to\pagewidth{\box0\hfil\box2}}% + \hbox to\txipagewidth{\box0\hfil\box2}% } @@ -5601,7 +6003,7 @@ end % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns - % and the final section into the vbox of \pageheight (see + % and the final section into the vbox of \txipageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the @@ -5612,24 +6014,30 @@ end % Split the last of the double-column material. \savemarks \balancecolumns - % + }% + \eject % call the \output just set + \ifdim\pagetotal=0pt % Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. \global\output = {\onepageout{\pagecontents\PAGE}}% - }% - \eject - \endgroup % started in \begindoublecolumns - \restoremarks - % Leave the double-column material on the current page, no automatic - % page break. - \box\balancedcolumns - % - % \pagegoal was set to the doubled \vsize above, since we restarted - % the current page. We're now back to normal single-column - % typesetting, so reset \pagegoal to the normal \vsize (after the - % \endgroup where \vsize got restored). - \pagegoal = \vsize + % + \endgroup % started in \begindoublecolumns + \restoremarks + % Leave the double-column material on the current page, no automatic + % page break. + \box\balancedcolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize. + \global\vsize = \txipageheight % + \pagegoal = \txipageheight % + \else + % We had some left-over material. This might happen when \doublecolumnout + % is called in \balancecolumns. Try again. + \expandafter\enddoublecolumns + \fi } \newbox\balancedcolumns \setbox\balancedcolumns=\vbox{shouldnt see this}% @@ -5637,46 +6045,54 @@ end % Only called for the last of the double column material. \doublecolumnout % does the others. \def\balancecolumns{% - \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip - \ifdim\dimen@<14\baselineskip + \ifdim\dimen@<5\baselineskip % Don't split a short final column in two. \setbox2=\vbox{}% + \global\setbox\balancedcolumns=\vbox{\pagesofar}% \else \divide\dimen@ by 2 % target to split to \dimen@ii = \dimen@ \splittopskip = \topskip - % Loop until the second column is no higher than the first + % Loop until left column is at least as high as the right column. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ - % Remove glue from bottom of first column to - % make sure it is higher than the second. - \global\setbox1 = \vbox{\unvbox1\unpenalty\unskip}% - \ifdim\ht3>\ht1 + \ifdim\ht1<\ht3 \global\advance\dimen@ by 1pt \repeat }% - \multiply\dimen@ii by 4 - \divide\dimen@ii by 5 - \ifdim\ht3<\dimen@ii - % Column heights are too different, so don't make their bottoms - % flush with each other. The glue at the end of the second column - % allows a second column to stretch, reducing the difference in - % height between the two. - \setbox0=\vbox to\dimen@{\unvbox1\vfill}% - \setbox2=\vbox to\dimen@{\unvbox3\vskip 0pt plus 0.3\ht0}% + % Now the left column is in box 1, and the right column in box 3. + % + % Check whether the left column has come out higher than the page itself. + % (Note that we have doubled \vsize for the double columns, so + % the actual height of the page is 0.5\vsize). + \ifdim2\ht1>\vsize + % It appears that we have been called upon to balance too much material. + % Output some of it with \doublecolumnout, leaving the rest on the page. + \setbox\PAGE=\box0 + \doublecolumnout \else - \setbox0=\vbox to\dimen@{\unvbox1}% - \setbox2=\vbox to\dimen@{\unvbox3}% + % Compare the heights of the two columns. + \ifdim4\ht1>5\ht3 + % Column heights are too different, so don't make their bottoms + % flush with each other. + \setbox2=\vbox to \ht1 {\unvbox3\vfill}% + \setbox0=\vbox to \ht1 {\unvbox1\vfill}% + \else + % Make column bottoms flush with each other. + \setbox2=\vbox to\ht1{\unvbox3\unskip}% + \setbox0=\vbox to\ht1{\unvbox1\unskip}% + \fi + \global\setbox\balancedcolumns=\vbox{\pagesofar}% \fi \fi % - \global\setbox\balancedcolumns=\vbox{\pagesofar}% } \catcode`\@ = \other @@ -5691,7 +6107,7 @@ end \null \vskip.3\vsize % move it down on the page a bit \begingroup - \noindent \titlefonts\rmisbold #1\par % the text + \noindent \titlefonts\rm #1\par % the text \let\lastnode=\empty % no node to associate with \writetocentry{part}{#1}{}% but put it in the toc \headingsoff % no headline or footline on the part page @@ -6085,7 +6501,7 @@ end \fi } -\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} +\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager @@ -6177,7 +6593,7 @@ end \domark % {% - \chapfonts \rmisbold + \chapfonts \rm \let\footnote=\errfootnoteheading % give better error message % % Have to define \lastsection before calling \donoderef, because the @@ -6231,30 +6647,6 @@ end } -% I don't think this chapter style is supported any more, so I'm not -% updating it with the new noderef stuff. We'll see. --karl, 11aug03. -% -\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} -% -\def\unnchfopen #1{% - \chapoddpage - \vbox{\chapfonts \raggedtitlesettings #1\par}% - \nobreak\bigskip\nobreak -} -\def\chfopen #1#2{\chapoddpage {\chapfonts -\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% -\par\penalty 5000 % -} -\def\centerchfopen #1{% - \chapoddpage - \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}% - \nobreak\bigskip \nobreak -} -\def\CHAPFopen{% - \global\let\chapmacro=\chfopen - \global\let\centerchapmacro=\centerchfopen} - - % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % @@ -6293,7 +6685,7 @@ end \let\footnote=\errfootnoteheading % % Switch to the right set of fonts. - \csname #2fonts\endcsname \rmisbold + \csname #2fonts\endcsname \rm % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs @@ -6457,7 +6849,14 @@ end % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. - \ifpdf \global\pdfmakepagedesttrue \fi + \ifpdf + \global\pdfmakepagedesttrue + \else + \ifx\XeTeXrevision\thisisundefined + \else + \global\pdfmakepagedesttrue + \fi + \fi } @@ -6600,7 +6999,15 @@ end % exist, with an empty box. Let's hope all the numbers have the same width. % Also ignore the page number, which is conventionally not printed. \def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} -\def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}} +\def\partentry#1#2#3#4{% + % Add stretch and a bonus for breaking the page before the part heading. + % This reduces the chance of the page being broken immediately after the + % part heading, before a following chapter heading. + \vskip 0pt plus 5\baselineskip + \penalty-300 + \vskip 0pt plus -5\baselineskip + \dochapentry{\numeralbox\labelspace#1}{}% +} % % Parts, in the short toc. \def\shortpartentry#1#2#3#4{% @@ -6717,7 +7124,6 @@ end \catcode `\>=\other \catcode `\`=\other \catcode `\'=\other - \escapechar=`\\ % % ' is active in math mode (mathcode"8000). So reset it, and all our % other math active characters (just in case), to plain's definitions. @@ -7560,7 +7966,7 @@ end \fi % no return type #3% output function name }% - {\rm\enskip}% hskip 0.5 em of \tenrm + {\rm\enskip}% hskip 0.5 em of \rmfont % \boldbrax % arguments will be output next, if any. @@ -7689,43 +8095,41 @@ end } \fi -\let\aftermacroxxx\relax -\def\aftermacro{\aftermacroxxx} - % alias because \c means cedilla in @tex or @math \let\texinfoc=\c +\newcount\savedcatcodeone +\newcount\savedcatcodetwo + % Used at the time of macro expansion. % Argument is macro body with arguments substituted \def\scanmacro#1{% \newlinechar`\^^M - \def\xprocessmacroarg{\eatspaces}% + \def\xeatspaces{\eatspaces}% + % + % Temporarily undo catcode changes of \printindex. Set catcode of @ to + % 0 so that @-commands in macro expansions aren't printed literally when + % formatting an index file, where \ is used as the escape character. + \savedcatcodeone=\catcode`\@ + \savedcatcodetwo=\catcode`\\ + \catcode`\@=0 + \catcode`\\=\active % % Process the macro body under the current catcode regime. - \scantokens{#1\texinfoc}\aftermacro% + \scantokens{#1@texinfoc}% + % + \catcode`\@=\savedcatcodeone + \catcode`\\=\savedcatcodetwo % - % The \c is to remove the \newlinechar added by \scantokens, and + % The \texinfoc is to remove the \newlinechar added by \scantokens, and % can be noticed by \parsearg. - % The \aftermacro allows a \comment at the end of the macro definition - % to duplicate itself past the final \newlinechar added by \scantokens: - % this is used in the definition of \group to comment out a newline. We - % don't do the same for \c to support Texinfo files with macros that ended - % with a @c, which should no longer be necessary. % We avoid surrounding the call to \scantokens with \bgroup and \egroup % to allow macros to open or close groups themselves. } % Used for copying and captions \def\scanexp#1{% - \bgroup - % Undo catcode changes of \startcontents and \printindex - % When called from @insertcopying or (short)caption, we need active - % backslash to get it printed correctly. - % FIXME: This may not be needed. - %\catcode`\@=0 \catcode`\\=\active \escapechar=`\@ - \edef\temp{\noexpand\scanmacro{#1}}% - \temp - \egroup + \expandafter\scanmacro\expandafter{#1}% } \newcount\paramno % Count of parameters @@ -7733,7 +8137,7 @@ end \newif\ifrecursive % Is it recursive? % List of all defined macros in the form -% \definedummyword\macro1\definedummyword\macro2... +% \commondummyword\macro1\commondummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} @@ -7741,7 +8145,7 @@ end % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% - \toks0 = \expandafter{\macrolist\definedummyword#1}% + \toks0 = \expandafter{\macrolist\commondummyword#1}% \xdef\macrolist{\the\toks0}% } @@ -7795,7 +8199,7 @@ end \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other - \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi + \passthroughcharstrue } \def\scanargctxt{% used for copying and captions, not macros. @@ -7882,7 +8286,7 @@ end % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax - \let\definedummyword\unmacrodo + \let\commondummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else @@ -7897,7 +8301,7 @@ end \ifx #1\relax % remove this \else - \noexpand\definedummyword \noexpand#1% + \noexpand\commondummyword \noexpand#1% \fi } @@ -7929,7 +8333,7 @@ end \paramno=0\def\paramlist{}% \let\hash\relax % \hash is redefined to `#' later to get it into definitions - \let\processmacroarg\relax + \let\xeatspaces\relax \parsemargdefxxx#1,;,% \ifnum\paramno<10\relax\else \paramno0\relax @@ -7941,7 +8345,7 @@ end \else \let\next=\parsemargdefxxx \advance\paramno by 1 \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname - {\processmacroarg{\hash\the\paramno}}% + {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} @@ -8167,128 +8571,75 @@ end %%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%% - -% Remove following spaces at the expansion stage. -% This works because spaces are discarded before each argument when TeX is -% getting the arguments for a macro. -% This must not be immediately followed by a }. -\long\def\gobblespaces#1{#1} - % This defines a Texinfo @macro or @rmacro, called by \parsemacbody. % \macrobody has the body of the macro in it, with placeholders for -% its parameters, looking like "\processmacroarg{\hash 1}". +% its parameters, looking like "\xeatspaces{\hash 1}". % \paramno is the number of parameters % \paramlist is a TeX parameter text, e.g. "#1,#2,#3," -% There are eight cases: recursive and nonrecursive macros of zero, one, -% up to nine, and many arguments. +% There are four cases: macros of zero, one, up to nine, and many arguments. % \xdef is used so that macro definitions will survive the file % they're defined in: @include reads the file inside a group. % \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifnum\paramno=1 - \def\processmacroarg{\gobblespaces}% + \def\xeatspaces##1{##1}% % This removes the pair of braces around the argument. We don't % use \eatspaces, because this can cause ends of lines to be lost % when the argument to \eatspaces is read, leading to line-based % commands like "@itemize" not being read correctly. \else - \def\processmacroarg{\xprocessmacroarg}% - \let\xprocessmacroarg\relax + \let\xeatspaces\relax % suppress expansion \fi - \ifrecursive %%%%%%%%%%%%%% Recursive %%%%%%%%%%%%%%%%%%%%%%%%%%%%% - \ifcase\paramno - % 0 - \expandafter\xdef\csname\the\macname\endcsname{% - \noexpand\scanmacro{\macrobody}}% - \or % 1 + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\spaceisspace + \noexpand\endlineisspace + \noexpand\expandafter % skip any whitespace after the macro name. + \expandafter\noexpand\csname\the\macname @@@\endcsname}% + \expandafter\xdef\csname\the\macname @@@\endcsname{% + \egroup + \noexpand\scanmacro{\macrobody}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname @@@\endcsname}% + \expandafter\xdef\csname\the\macname @@@\endcsname##1{% + \egroup + \noexpand\scanmacro{\macrobody}% + }% + \else % at most 9 + \ifnum\paramno<10\relax + % @MACNAME sets the context for reading the macro argument + % @MACNAME@@ gets the argument, processes backslashes and appends a + % comma. + % @MACNAME@@@ removes braces surrounding the argument list. + % @MACNAME@@@@ scans the macro body with arguments substituted. \expandafter\xdef\csname\the\macname\endcsname{% - \bgroup - \noexpand\braceorline - \expandafter\noexpand\csname\the\macname @@@\endcsname}% + \bgroup + \noexpand\expandafter % This \expandafter skip any spaces after the + \noexpand\macroargctxt % macro before we change the catcode of space. + \noexpand\expandafter + \expandafter\noexpand\csname\the\macname @@\endcsname}% + \expandafter\xdef\csname\the\macname @@\endcsname##1{% + \noexpand\passargtomacro + \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% - \expandafter\noexpand\csname\the\macname @@@@\endcsname{% - \noexpand\gobblespaces##1\empty}% - % The \empty is for \gobblespaces in case #1 is empty - }% - \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% - \egroup\noexpand\scanmacro{\macrobody}}% - \else - \ifnum\paramno<10\relax % at most 9 - % See non-recursive section below for comments - \expandafter\xdef\csname\the\macname\endcsname{% - \bgroup - \noexpand\expandafter - \noexpand\macroargctxt - \noexpand\expandafter - \expandafter\noexpand\csname\the\macname @@\endcsname}% - \expandafter\xdef\csname\the\macname @@\endcsname##1{% - \noexpand\passargtomacro - \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% - \expandafter\xdef\csname\the\macname @@@\endcsname##1{% - \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% - \expandafter\expandafter - \expandafter\xdef - \expandafter\expandafter - \csname\the\macname @@@@\endcsname\paramlist{% - \egroup\noexpand\scanmacro{\macrobody}}% - \else % 10 or more - \expandafter\xdef\csname\the\macname\endcsname{% - \noexpand\getargvals@{\the\macname}{\argl}% - }% - \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody - \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble - \fi - \fi - \else %%%%%%%%%%%%%%%%%%%%%% Non-recursive %%%%%%%%%%%%%%%%%%%%%%%%%% - \ifcase\paramno - % 0 - \expandafter\xdef\csname\the\macname\endcsname{% - \noexpand\scanmacro{\macrobody}}% - \or % 1 + \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname @@@@\endcsname\paramlist{% + \egroup\noexpand\scanmacro{\macrobody}}% + \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% - \bgroup - \noexpand\braceorline - \expandafter\noexpand\csname\the\macname @@@\endcsname}% - \expandafter\xdef\csname\the\macname @@@\endcsname##1{% - \expandafter\noexpand\csname\the\macname @@@@\endcsname{% - \noexpand\gobblespaces##1\empty}% - % The \empty is for \gobblespaces in case #1 is empty - }% - \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% - \egroup - \noexpand\scanmacro{\macrobody}% - }% - \else % at most 9 - \ifnum\paramno<10\relax - % @MACNAME sets the context for reading the macro argument - % @MACNAME@@ gets the argument, processes backslashes and appends a - % comma. - % @MACNAME@@@ removes braces surrounding the argument list. - % @MACNAME@@@@ scans the macro body with arguments substituted. - \expandafter\xdef\csname\the\macname\endcsname{% - \bgroup - \noexpand\expandafter % This \expandafter skip any spaces after the - \noexpand\macroargctxt % macro before we change the catcode of space. - \noexpand\expandafter - \expandafter\noexpand\csname\the\macname @@\endcsname}% - \expandafter\xdef\csname\the\macname @@\endcsname##1{% - \noexpand\passargtomacro - \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% - \expandafter\xdef\csname\the\macname @@@\endcsname##1{% - \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% - \expandafter\expandafter - \expandafter\xdef - \expandafter\expandafter - \csname\the\macname @@@@\endcsname\paramlist{% - \egroup\noexpand\scanmacro{\macrobody}}% - \else % 10 or more: - \expandafter\xdef\csname\the\macname\endcsname{% - \noexpand\getargvals@{\the\macname}{\argl}% - }% - \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody - \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse - \fi + \noexpand\getargvals@{\the\macname}{\argl}% + }% + \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody + \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi} @@ -8484,6 +8835,8 @@ end {% \requireauxfile \atdummies % preserve commands, but don't expand them + % match definition in \xrdef, \refx, \xrefX. + \def\value##1{##1}% \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef @@ -8574,9 +8927,10 @@ end % % Make link in pdf output. \ifpdf + % For pdfTeX and LuaTeX {\indexnofonts - \turnoffactive \makevalueexpandable + \turnoffactive % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. @@ -8584,28 +8938,67 @@ end % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. - \edef\pdfxrefdest{#1}% - \ifx\pdfxrefdest\empty - \def\pdfxrefdest{Top}% no empty targets - \else - \txiescapepdf\pdfxrefdest % escape PDF special chars + \setpdfdestname{#1}% + % + \ifx\pdfdestname\empty + \def\pdfdestname{Top}% no empty targets \fi % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 - goto file{\the\filename.pdf} name{\pdfxrefdest}% + goto file{\the\filename.pdf} name{\pdfdestname}% \else - goto name{\pdfmkpgn{\pdfxrefdest}}% + goto name{\pdfmkpgn{\pdfdestname}}% \fi }% \setcolor{\linkcolor}% + \else + \ifx\XeTeXrevision\thisisundefined + \else + % For XeTeX + {\indexnofonts + \makevalueexpandable + \turnoffactive + % This expands tokens, so do it after making catcode changes, so _ + % etc. don't get their TeX definitions. This ignores all spaces in + % #4, including (wrongly) those in the middle of the filename. + \getfilename{#4}% + % + % This (wrongly) does not take account of leading or trailing + % spaces in #1, which should be ignored. + \setpdfdestname{#1}% + % + \ifx\pdfdestname\empty + \def\pdfdestname{Top}% no empty targets + \fi + % + \leavevmode + \ifnum\filenamelength>0 + % With default settings, + % XeTeX (xdvipdfmx) replaces link destination names with integers. + % In this case, the replaced destination names of + % remote PDFs are no longer known. In order to avoid a replacement, + % you can use xdvipdfmx's command line option `-C 0x0010'. + % If you use XeTeX 0.99996+ (TeX Live 2016+), + % this command line option is no longer necessary + % because we can use the `dvipdfmx:config' special. + \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A + << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}% + \else + \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A + << /S /GoTo /D (\pdfdestname) >> >>}% + \fi + }% + \setcolor{\linkcolor}% + \fi \fi {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive + \def\value##1{##1}% \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% @@ -8746,14 +9139,14 @@ end \fi\fi\fi } -% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. -% If its value is nonempty, SUFFIX is output afterward. -% +% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME. SUFFIX +% is output afterwards if non-empty. \def\refx#1#2{% \requireauxfile {% \indexnofonts \otherbackslash + \def\value##1{##1}% \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% @@ -8778,20 +9171,28 @@ end #2% Output the suffix in any case. } -% This is the macro invoked by entries in the aux file. Usually it's -% just a \def (we prepend XR to the control sequence name to avoid -% collisions). But if this is a float type, we have more work to do. +% This is the macro invoked by entries in the aux file. Define a control +% sequence for a cross-reference target (we prepend XR to the control sequence +% name to avoid collisions). The value is the page number. If this is a float +% type, we have more work to do. % \def\xrdef#1#2{% - {% The node name might contain 8-bit characters, which in our current - % implementation are changed to commands like @'e. Don't let these - % mess up the control sequence name. + {% Expand the node or anchor name to remove control sequences. + % \turnoffactive stops 8-bit characters being changed to commands + % like @'e. \refx does the same to retrieve the value in the definition. \indexnofonts \turnoffactive + \def\value##1{##1}% \xdef\safexrefname{#1}% }% % - \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref + \bgroup + \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% + \egroup + % We put the \gdef inside a group to avoid the definitions building up on + % TeX's save stack, which can cause it to run out of space for aux files with + % thousands of lines. \gdef doesn't use the save stack, but \csname does + % when it defines an unknown control sequence as \relax. % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname @@ -8909,9 +9310,6 @@ end % now. --karl, 15jan04. \catcode`\\=\other % - % Make the characters 128-255 be printing characters. - {\setnonasciicharscatcodenonglobal\other}% - % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 @@ -8975,7 +9373,7 @@ end % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. - \hsize=\pagewidth + \hsize=\txipagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox @@ -9100,7 +9498,7 @@ end \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get - it from ftp://tug.org/tex/epsf.tex.} + it from https://ctan.org/texarchive/macros/texinfo/texinfo/doc/epsf.tex.} % \def\image#1{% \ifx\epsfbox\thisisundefined @@ -9290,7 +9688,7 @@ end % \ifx\thiscaption\empty \else \ifx\floatident\empty \else - \appendtomacro\captionline{: }% had ident, so need a colon between + \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. @@ -9317,30 +9715,17 @@ end \requireauxfile \atdummies % - % since we read the caption text in the macro world, where ^^M - % is turned into a normal character, we have to scan it back, so - % we don't write the literal three characters "^^M" into the aux file. - \scanexp{% - \xdef\noexpand\gtemp{% - \ifx\thisshortcaption\empty - \thiscaption - \else - \thisshortcaption - \fi - }% - }% + \ifx\thisshortcaption\empty + \def\gtemp{\thiscaption}% + \else + \def\gtemp{\thisshortcaption}% + \fi \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident - \ifx\gtemp\empty \else : \gtemp \fi}}% + \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % - % place the captured inserts - % - % BEWARE: when the floats start floating, we have to issue warning - % whenever an insert appears inside a float which could possibly - % float. --kasal, 26may04 - % \checkinserts } @@ -9515,43 +9900,68 @@ directory should work if nowhere else does.} \global\righthyphenmin = #3\relax } -% Get input by bytes instead of by UTF-8 codepoints for XeTeX and LuaTeX, -% otherwise the encoding support is completely broken. +% XeTeX and LuaTeX can handle Unicode natively. +% Their default I/O uses UTF-8 sequences instead of a byte-wise operation. +% Other TeX engines' I/O (pdfTeX, etc.) is byte-wise. +% +\newif\iftxinativeunicodecapable +\newif\iftxiusebytewiseio + \ifx\XeTeXrevision\thisisundefined + \ifx\luatexversion\thisisundefined + \txinativeunicodecapablefalse + \txiusebytewiseiotrue + \else + \txinativeunicodecapabletrue + \txiusebytewiseiofalse + \fi \else -\XeTeXdefaultencoding "bytes" % For subsequent files to be read -\XeTeXinputencoding "bytes" % Effective in texinfo.tex only -% Unfortunately, there seems to be no corresponding XeTeX command for -% output encoding. This is a problem for auxiliary index and TOC files. -% The only solution would be perhaps to write out @U{...} sequences in -% place of UTF-8 characters. + \txinativeunicodecapabletrue + \txiusebytewiseiofalse \fi -\ifx\luatexversion\thisisundefined -\else -\directlua{ -local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub -local function convert_char (char) - return utf8_char(byte(char)) -end - -local function convert_line (line) - return gsub(line, ".", convert_char) -end - -callback.register("process_input_buffer", convert_line) +% Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex +% for non-UTF-8 (byte-wise) encodings. +% +\def\setbytewiseio{% + \ifx\XeTeXrevision\thisisundefined + \else + \XeTeXdefaultencoding "bytes" % For subsequent files to be read + \XeTeXinputencoding "bytes" % For document root file + % Unfortunately, there seems to be no corresponding XeTeX command for + % output encoding. This is a problem for auxiliary index and TOC files. + % The only solution would be perhaps to write out @U{...} sequences in + % place of non-ASCII characters. + \fi -local function convert_line_out (line) - local line_out = "" - for c in string.utfvalues(line) do - line_out = line_out .. string.char(c) - end - return line_out -end + \ifx\luatexversion\thisisundefined + \else + \directlua{ + local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub + local function convert_char (char) + return utf8_char(byte(char)) + end + + local function convert_line (line) + return gsub(line, ".", convert_char) + end + + callback.register("process_input_buffer", convert_line) + + local function convert_line_out (line) + local line_out = "" + for c in string.utfvalues(line) do + line_out = line_out .. string.char(c) + end + return line_out + end + + callback.register("process_output_buffer", convert_line_out) + } + \fi -callback.register("process_output_buffer", convert_line_out) + \txiusebytewiseiotrue } -\fi % Helpers for encodings. @@ -9578,13 +9988,6 @@ callback.register("process_output_buffer", convert_line_out) % \def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz} \def\documentencodingzzz#1{% - % Get input by bytes instead of by UTF-8 codepoints for XeTeX, - % otherwise the encoding support is completely broken. - % This settings is for the document root file. - \ifx\XeTeXrevision\thisisundefined - \else - \XeTeXinputencoding "bytes" - \fi % % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% @@ -9601,22 +10004,38 @@ callback.register("process_output_buffer", convert_line_out) \asciichardefs % \else \ifx \declaredencoding \lattwo + \iftxinativeunicodecapable + \setbytewiseio + \fi \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone + \iftxinativeunicodecapable + \setbytewiseio + \fi \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine + \iftxinativeunicodecapable + \setbytewiseio + \fi \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight - \setnonasciicharscatcode\active - % since we already invoked \utfeightchardefs at the top level - % (below), do not re-invoke it, then our check for duplicated - % definitions triggers. Making non-ascii chars active is enough. + \iftxinativeunicodecapable + % For native Unicode handling (XeTeX and LuaTeX) + \nativeunicodechardefs + \else + % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX) + \setnonasciicharscatcode\active + % since we already invoked \utfeightchardefs at the top level + % (below), do not re-invoke it, otherwise our check for duplicated + % definitions gets triggered. Making non-ascii chars active is + % sufficient. + \fi % \else \message{Ignoring unknown document encoding: #1.}% @@ -9626,6 +10045,18 @@ callback.register("process_output_buffer", convert_line_out) \fi % latone \fi % lattwo \fi % ascii + % + \ifx\XeTeXrevision\thisisundefined + \else + \ifx \declaredencoding \utfeight + \else + \ifx \declaredencoding \ascii + \else + \message{Warning: XeTeX with non-UTF-8 encodings cannot handle % + non-ASCII characters in auxiliary files.}% + \fi + \fi + \fi } % emacs-page @@ -9642,109 +10073,119 @@ callback.register("process_output_buffer", convert_line_out) % macros containing the character definitions. \setnonasciicharscatcode\active % + +\def\gdefchar#1#2{% +\gdef#1{% + \ifpassthroughchars + \string#1% + \else + #2% + \fi +}} + % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% - \gdef^^a0{\tie} - \gdef^^a1{\exclamdown} - \gdef^^a2{{\tcfont \char162}} % cent - \gdef^^a3{\pounds} - \gdef^^a4{{\tcfont \char164}} % currency - \gdef^^a5{{\tcfont \char165}} % yen - \gdef^^a6{{\tcfont \char166}} % broken bar - \gdef^^a7{\S} - \gdef^^a8{\"{}} - \gdef^^a9{\copyright} - \gdef^^aa{\ordf} - \gdef^^ab{\guillemetleft} - \gdef^^ac{\ensuremath\lnot} - \gdef^^ad{\-} - \gdef^^ae{\registeredsymbol} - \gdef^^af{\={}} - % - \gdef^^b0{\textdegree} - \gdef^^b1{$\pm$} - \gdef^^b2{$^2$} - \gdef^^b3{$^3$} - \gdef^^b4{\'{}} - \gdef^^b5{$\mu$} - \gdef^^b6{\P} - \gdef^^b7{\ensuremath\cdot} - \gdef^^b8{\cedilla\ } - \gdef^^b9{$^1$} - \gdef^^ba{\ordm} - \gdef^^bb{\guillemetright} - \gdef^^bc{$1\over4$} - \gdef^^bd{$1\over2$} - \gdef^^be{$3\over4$} - \gdef^^bf{\questiondown} - % - \gdef^^c0{\`A} - \gdef^^c1{\'A} - \gdef^^c2{\^A} - \gdef^^c3{\~A} - \gdef^^c4{\"A} - \gdef^^c5{\ringaccent A} - \gdef^^c6{\AE} - \gdef^^c7{\cedilla C} - \gdef^^c8{\`E} - \gdef^^c9{\'E} - \gdef^^ca{\^E} - \gdef^^cb{\"E} - \gdef^^cc{\`I} - \gdef^^cd{\'I} - \gdef^^ce{\^I} - \gdef^^cf{\"I} - % - \gdef^^d0{\DH} - \gdef^^d1{\~N} - \gdef^^d2{\`O} - \gdef^^d3{\'O} - \gdef^^d4{\^O} - \gdef^^d5{\~O} - \gdef^^d6{\"O} - \gdef^^d7{$\times$} - \gdef^^d8{\O} - \gdef^^d9{\`U} - \gdef^^da{\'U} - \gdef^^db{\^U} - \gdef^^dc{\"U} - \gdef^^dd{\'Y} - \gdef^^de{\TH} - \gdef^^df{\ss} - % - \gdef^^e0{\`a} - \gdef^^e1{\'a} - \gdef^^e2{\^a} - \gdef^^e3{\~a} - \gdef^^e4{\"a} - \gdef^^e5{\ringaccent a} - \gdef^^e6{\ae} - \gdef^^e7{\cedilla c} - \gdef^^e8{\`e} - \gdef^^e9{\'e} - \gdef^^ea{\^e} - \gdef^^eb{\"e} - \gdef^^ec{\`{\dotless i}} - \gdef^^ed{\'{\dotless i}} - \gdef^^ee{\^{\dotless i}} - \gdef^^ef{\"{\dotless i}} - % - \gdef^^f0{\dh} - \gdef^^f1{\~n} - \gdef^^f2{\`o} - \gdef^^f3{\'o} - \gdef^^f4{\^o} - \gdef^^f5{\~o} - \gdef^^f6{\"o} - \gdef^^f7{$\div$} - \gdef^^f8{\o} - \gdef^^f9{\`u} - \gdef^^fa{\'u} - \gdef^^fb{\^u} - \gdef^^fc{\"u} - \gdef^^fd{\'y} - \gdef^^fe{\th} - \gdef^^ff{\"y} + \gdefchar^^a0{\tie} + \gdefchar^^a1{\exclamdown} + \gdefchar^^a2{{\tcfont \char162}} % cent + \gdefchar^^a3{\pounds{}} + \gdefchar^^a4{{\tcfont \char164}} % currency + \gdefchar^^a5{{\tcfont \char165}} % yen + \gdefchar^^a6{{\tcfont \char166}} % broken bar + \gdefchar^^a7{\S} + \gdefchar^^a8{\"{}} + \gdefchar^^a9{\copyright{}} + \gdefchar^^aa{\ordf} + \gdefchar^^ab{\guillemetleft{}} + \gdefchar^^ac{\ensuremath\lnot} + \gdefchar^^ad{\-} + \gdefchar^^ae{\registeredsymbol{}} + \gdefchar^^af{\={}} + % + \gdefchar^^b0{\textdegree} + \gdefchar^^b1{$\pm$} + \gdefchar^^b2{$^2$} + \gdefchar^^b3{$^3$} + \gdefchar^^b4{\'{}} + \gdefchar^^b5{$\mu$} + \gdefchar^^b6{\P} + \gdefchar^^b7{\ensuremath\cdot} + \gdefchar^^b8{\cedilla\ } + \gdefchar^^b9{$^1$} + \gdefchar^^ba{\ordm} + \gdefchar^^bb{\guillemetright{}} + \gdefchar^^bc{$1\over4$} + \gdefchar^^bd{$1\over2$} + \gdefchar^^be{$3\over4$} + \gdefchar^^bf{\questiondown} + % + \gdefchar^^c0{\`A} + \gdefchar^^c1{\'A} + \gdefchar^^c2{\^A} + \gdefchar^^c3{\~A} + \gdefchar^^c4{\"A} + \gdefchar^^c5{\ringaccent A} + \gdefchar^^c6{\AE} + \gdefchar^^c7{\cedilla C} + \gdefchar^^c8{\`E} + \gdefchar^^c9{\'E} + \gdefchar^^ca{\^E} + \gdefchar^^cb{\"E} + \gdefchar^^cc{\`I} + \gdefchar^^cd{\'I} + \gdefchar^^ce{\^I} + \gdefchar^^cf{\"I} + % + \gdefchar^^d0{\DH} + \gdefchar^^d1{\~N} + \gdefchar^^d2{\`O} + \gdefchar^^d3{\'O} + \gdefchar^^d4{\^O} + \gdefchar^^d5{\~O} + \gdefchar^^d6{\"O} + \gdefchar^^d7{$\times$} + \gdefchar^^d8{\O} + \gdefchar^^d9{\`U} + \gdefchar^^da{\'U} + \gdefchar^^db{\^U} + \gdefchar^^dc{\"U} + \gdefchar^^dd{\'Y} + \gdefchar^^de{\TH} + \gdefchar^^df{\ss} + % + \gdefchar^^e0{\`a} + \gdefchar^^e1{\'a} + \gdefchar^^e2{\^a} + \gdefchar^^e3{\~a} + \gdefchar^^e4{\"a} + \gdefchar^^e5{\ringaccent a} + \gdefchar^^e6{\ae} + \gdefchar^^e7{\cedilla c} + \gdefchar^^e8{\`e} + \gdefchar^^e9{\'e} + \gdefchar^^ea{\^e} + \gdefchar^^eb{\"e} + \gdefchar^^ec{\`{\dotless i}} + \gdefchar^^ed{\'{\dotless i}} + \gdefchar^^ee{\^{\dotless i}} + \gdefchar^^ef{\"{\dotless i}} + % + \gdefchar^^f0{\dh} + \gdefchar^^f1{\~n} + \gdefchar^^f2{\`o} + \gdefchar^^f3{\'o} + \gdefchar^^f4{\^o} + \gdefchar^^f5{\~o} + \gdefchar^^f6{\"o} + \gdefchar^^f7{$\div$} + \gdefchar^^f8{\o} + \gdefchar^^f9{\`u} + \gdefchar^^fa{\'u} + \gdefchar^^fb{\^u} + \gdefchar^^fc{\"u} + \gdefchar^^fd{\'y} + \gdefchar^^fe{\th} + \gdefchar^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. @@ -9752,119 +10193,119 @@ callback.register("process_output_buffer", convert_line_out) % Encoding is almost identical to Latin1. \latonechardefs % - \gdef^^a4{\euro} - \gdef^^a6{\v S} - \gdef^^a8{\v s} - \gdef^^b4{\v Z} - \gdef^^b8{\v z} - \gdef^^bc{\OE} - \gdef^^bd{\oe} - \gdef^^be{\"Y} + \gdefchar^^a4{\euro{}} + \gdefchar^^a6{\v S} + \gdefchar^^a8{\v s} + \gdefchar^^b4{\v Z} + \gdefchar^^b8{\v z} + \gdefchar^^bc{\OE} + \gdefchar^^bd{\oe} + \gdefchar^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% - \gdef^^a0{\tie} - \gdef^^a1{\ogonek{A}} - \gdef^^a2{\u{}} - \gdef^^a3{\L} - \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} - \gdef^^a5{\v L} - \gdef^^a6{\'S} - \gdef^^a7{\S} - \gdef^^a8{\"{}} - \gdef^^a9{\v S} - \gdef^^aa{\cedilla S} - \gdef^^ab{\v T} - \gdef^^ac{\'Z} - \gdef^^ad{\-} - \gdef^^ae{\v Z} - \gdef^^af{\dotaccent Z} - % - \gdef^^b0{\textdegree} - \gdef^^b1{\ogonek{a}} - \gdef^^b2{\ogonek{ }} - \gdef^^b3{\l} - \gdef^^b4{\'{}} - \gdef^^b5{\v l} - \gdef^^b6{\'s} - \gdef^^b7{\v{}} - \gdef^^b8{\cedilla\ } - \gdef^^b9{\v s} - \gdef^^ba{\cedilla s} - \gdef^^bb{\v t} - \gdef^^bc{\'z} - \gdef^^bd{\H{}} - \gdef^^be{\v z} - \gdef^^bf{\dotaccent z} - % - \gdef^^c0{\'R} - \gdef^^c1{\'A} - \gdef^^c2{\^A} - \gdef^^c3{\u A} - \gdef^^c4{\"A} - \gdef^^c5{\'L} - \gdef^^c6{\'C} - \gdef^^c7{\cedilla C} - \gdef^^c8{\v C} - \gdef^^c9{\'E} - \gdef^^ca{\ogonek{E}} - \gdef^^cb{\"E} - \gdef^^cc{\v E} - \gdef^^cd{\'I} - \gdef^^ce{\^I} - \gdef^^cf{\v D} - % - \gdef^^d0{\DH} - \gdef^^d1{\'N} - \gdef^^d2{\v N} - \gdef^^d3{\'O} - \gdef^^d4{\^O} - \gdef^^d5{\H O} - \gdef^^d6{\"O} - \gdef^^d7{$\times$} - \gdef^^d8{\v R} - \gdef^^d9{\ringaccent U} - \gdef^^da{\'U} - \gdef^^db{\H U} - \gdef^^dc{\"U} - \gdef^^dd{\'Y} - \gdef^^de{\cedilla T} - \gdef^^df{\ss} - % - \gdef^^e0{\'r} - \gdef^^e1{\'a} - \gdef^^e2{\^a} - \gdef^^e3{\u a} - \gdef^^e4{\"a} - \gdef^^e5{\'l} - \gdef^^e6{\'c} - \gdef^^e7{\cedilla c} - \gdef^^e8{\v c} - \gdef^^e9{\'e} - \gdef^^ea{\ogonek{e}} - \gdef^^eb{\"e} - \gdef^^ec{\v e} - \gdef^^ed{\'{\dotless{i}}} - \gdef^^ee{\^{\dotless{i}}} - \gdef^^ef{\v d} - % - \gdef^^f0{\dh} - \gdef^^f1{\'n} - \gdef^^f2{\v n} - \gdef^^f3{\'o} - \gdef^^f4{\^o} - \gdef^^f5{\H o} - \gdef^^f6{\"o} - \gdef^^f7{$\div$} - \gdef^^f8{\v r} - \gdef^^f9{\ringaccent u} - \gdef^^fa{\'u} - \gdef^^fb{\H u} - \gdef^^fc{\"u} - \gdef^^fd{\'y} - \gdef^^fe{\cedilla t} - \gdef^^ff{\dotaccent{}} + \gdefchar^^a0{\tie} + \gdefchar^^a1{\ogonek{A}} + \gdefchar^^a2{\u{}} + \gdefchar^^a3{\L} + \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdefchar^^a5{\v L} + \gdefchar^^a6{\'S} + \gdefchar^^a7{\S} + \gdefchar^^a8{\"{}} + \gdefchar^^a9{\v S} + \gdefchar^^aa{\cedilla S} + \gdefchar^^ab{\v T} + \gdefchar^^ac{\'Z} + \gdefchar^^ad{\-} + \gdefchar^^ae{\v Z} + \gdefchar^^af{\dotaccent Z} + % + \gdefchar^^b0{\textdegree{}} + \gdefchar^^b1{\ogonek{a}} + \gdefchar^^b2{\ogonek{ }} + \gdefchar^^b3{\l} + \gdefchar^^b4{\'{}} + \gdefchar^^b5{\v l} + \gdefchar^^b6{\'s} + \gdefchar^^b7{\v{}} + \gdefchar^^b8{\cedilla\ } + \gdefchar^^b9{\v s} + \gdefchar^^ba{\cedilla s} + \gdefchar^^bb{\v t} + \gdefchar^^bc{\'z} + \gdefchar^^bd{\H{}} + \gdefchar^^be{\v z} + \gdefchar^^bf{\dotaccent z} + % + \gdefchar^^c0{\'R} + \gdefchar^^c1{\'A} + \gdefchar^^c2{\^A} + \gdefchar^^c3{\u A} + \gdefchar^^c4{\"A} + \gdefchar^^c5{\'L} + \gdefchar^^c6{\'C} + \gdefchar^^c7{\cedilla C} + \gdefchar^^c8{\v C} + \gdefchar^^c9{\'E} + \gdefchar^^ca{\ogonek{E}} + \gdefchar^^cb{\"E} + \gdefchar^^cc{\v E} + \gdefchar^^cd{\'I} + \gdefchar^^ce{\^I} + \gdefchar^^cf{\v D} + % + \gdefchar^^d0{\DH} + \gdefchar^^d1{\'N} + \gdefchar^^d2{\v N} + \gdefchar^^d3{\'O} + \gdefchar^^d4{\^O} + \gdefchar^^d5{\H O} + \gdefchar^^d6{\"O} + \gdefchar^^d7{$\times$} + \gdefchar^^d8{\v R} + \gdefchar^^d9{\ringaccent U} + \gdefchar^^da{\'U} + \gdefchar^^db{\H U} + \gdefchar^^dc{\"U} + \gdefchar^^dd{\'Y} + \gdefchar^^de{\cedilla T} + \gdefchar^^df{\ss} + % + \gdefchar^^e0{\'r} + \gdefchar^^e1{\'a} + \gdefchar^^e2{\^a} + \gdefchar^^e3{\u a} + \gdefchar^^e4{\"a} + \gdefchar^^e5{\'l} + \gdefchar^^e6{\'c} + \gdefchar^^e7{\cedilla c} + \gdefchar^^e8{\v c} + \gdefchar^^e9{\'e} + \gdefchar^^ea{\ogonek{e}} + \gdefchar^^eb{\"e} + \gdefchar^^ec{\v e} + \gdefchar^^ed{\'{\dotless{i}}} + \gdefchar^^ee{\^{\dotless{i}}} + \gdefchar^^ef{\v d} + % + \gdefchar^^f0{\dh} + \gdefchar^^f1{\'n} + \gdefchar^^f2{\v n} + \gdefchar^^f3{\'o} + \gdefchar^^f4{\^o} + \gdefchar^^f5{\H o} + \gdefchar^^f6{\"o} + \gdefchar^^f7{$\div$} + \gdefchar^^f8{\v r} + \gdefchar^^f9{\ringaccent u} + \gdefchar^^fa{\'u} + \gdefchar^^fb{\H u} + \gdefchar^^fc{\"u} + \gdefchar^^fd{\'y} + \gdefchar^^fe{\cedilla t} + \gdefchar^^ff{\dotaccent{}} } % UTF-8 character definitions. @@ -9894,35 +10335,56 @@ callback.register("process_output_buffer", convert_line_out) \fi } +% Give non-ASCII bytes the active definitions for processing UTF-8 sequences \begingroup \catcode`\~13 + \catcode`\$12 \catcode`\"12 + % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp + % substituting ~ and $ with a character token of that value. \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx + \uccode`\$\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} + % For bytes other than the first in a UTF-8 sequence. Not expected to + % be expanded except when writing to auxiliary files. + \countUTFx = "80 + \countUTFy = "C2 + \def\UTFviiiTmp{% + \gdef~{% + \ifpassthroughchars $\fi}}% + \UTFviiiLoop + \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% - \xdef~{\noexpand\UTFviiiTwoOctets\string~}} + \gdef~{% + \ifpassthroughchars $% + \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}% \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% - \xdef~{\noexpand\UTFviiiThreeOctets\string~}} + \gdef~{% + \ifpassthroughchars $% + \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}% \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% - \xdef~{\noexpand\UTFviiiFourOctets\string~}} + \gdef~{% + \ifpassthroughchars $% + \else\expandafter\UTFviiiFourOctets\expandafter$\fi + }}% \UTFviiiLoop \endgroup @@ -9931,13 +10393,36 @@ callback.register("process_output_buffer", convert_line_out) % @U{xxxx} to produce U+xxxx, if we support it. \def\U#1{% \expandafter\ifx\csname uni:#1\endcsname \relax - \errhelp = \EMsimple - \errmessage{Unicode character U+#1 not supported, sorry}% + \iftxinativeunicodecapable + % All Unicode characters can be used if native Unicode handling is + % active. However, if the font does not have the glyph, + % letters are missing. + \begingroup + \uccode`\.="#1\relax + \uppercase{.} + \endgroup + \else + \errhelp = \EMsimple + \errmessage{Unicode character U+#1 not supported, sorry}% + \fi \else \csname uni:#1\endcsname \fi } +% These macros are used here to construct the name of a control +% sequence to be defined. +\def\UTFviiiTwoOctetsName#1#2{% + \csname u8:#1\string #2\endcsname}% +\def\UTFviiiThreeOctetsName#1#2#3{% + \csname u8:#1\string #2\string #3\endcsname}% +\def\UTFviiiFourOctetsName#1#2#3#4{% + \csname u8:#1\string #2\string #3\string #4\endcsname}% + +% For UTF-8 byte sequences (TeX, e-TeX and pdfTeX), +% provide a definition macro to replace a Unicode character; +% this gets used by the @U command +% \begingroup \catcode`\"=12 \catcode`\<=12 @@ -9946,20 +10431,22 @@ callback.register("process_output_buffer", convert_line_out) \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 - \gdef\DeclareUnicodeCharacter#1#2{% + \gdef\DeclareUnicodeCharacterUTFviii#1#2{% \countUTFz = "#1\relax - %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref - \def\UTFviiiTwoOctets##1##2{% - \csname u8:##1\string ##2\endcsname}% - \def\UTFviiiThreeOctets##1##2##3{% - \csname u8:##1\string ##2\string ##3\endcsname}% - \def\UTFviiiFourOctets##1##2##3##4{% - \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% - \expandafter\expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter - \gdef\UTFviiiTmp{#2}% + + % Give \u8:... its definition. The sequence of seven \expandafter's + % expands after the \gdef three times, e.g. + % + % 1. \UTFviiTwoOctetsName B1 B2 + % 2. \csname u8:B1 \string B2 \endcsname + % 3. \u8: B1 B2 (a single control sequence token) + % + \expandafter\expandafter + \expandafter\expandafter + \expandafter\expandafter + \expandafter\gdef \UTFviiiTmp{#2}% % \expandafter\ifx\csname uni:#1\endcsname \relax \else \message{Internal error, already defined: #1}% @@ -9968,42 +10455,67 @@ callback.register("process_output_buffer", convert_line_out) % define an additional control sequence for this code point. \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp \endgroup} - + % + % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp + % to the corresponding UTF-8 sequence. \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% - \parseUTFviiiB C\UTFviiiTwoOctets.,% + \parseUTFviiiB C\UTFviiiTwoOctetsName.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% - \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% + \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% - \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% + \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}% \fi\fi\fi } + % Extract a byte from the end of the UTF-8 representation of \countUTFx. + % It must be a non-initial byte in the sequence. + % Change \uccode of #1 for it to be used in \parseUTFviiiB as one + % of the bytes. \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 - \countUTFy = \countUTFz + \countUTFy = \countUTFz % Save to be the future value of \countUTFz. \multiply\countUTFz by 64 + + % \countUTFz is now \countUTFx with the last 5 bits cleared. Subtract + % in order to get the last five bits. \advance\countUTFx by -\countUTFz + + % Convert this to the byte in the UTF-8 sequence. \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} + % Used to put a UTF-8 byte sequence into \UTFviiiTmp + % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8 + % sequence. + % #2 is one of the \UTFviii*OctetsName macros. + % #3 is always a full stop (.) + % #4 is a template for the other bytes in the sequence. The values for these + % bytes is substituted in here with \uppercase using the \uccode's. \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup +% For native Unicode handling (XeTeX and LuaTeX), +% provide a definition macro that sets a catcode to `other' non-globally +% +\def\DeclareUnicodeCharacterNativeOther#1#2{% + \catcode"#1=\other +} + % https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M % U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block) % U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block) @@ -10018,732 +10530,738 @@ callback.register("process_output_buffer", convert_line_out) % We won't be doing that here in this simple file. But we can try to at % least make most of the characters not bomb out. % -\def\utfeightchardefs{% - \DeclareUnicodeCharacter{00A0}{\tie} - \DeclareUnicodeCharacter{00A1}{\exclamdown} +\def\unicodechardefs{% + \DeclareUnicodeCharacter{00A0}{\tie}% + \DeclareUnicodeCharacter{00A1}{\exclamdown}% \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent - \DeclareUnicodeCharacter{00A3}{\pounds} + \DeclareUnicodeCharacter{00A3}{\pounds{}}% \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar - \DeclareUnicodeCharacter{00A7}{\S} - \DeclareUnicodeCharacter{00A8}{\"{ }} - \DeclareUnicodeCharacter{00A9}{\copyright} - \DeclareUnicodeCharacter{00AA}{\ordf} - \DeclareUnicodeCharacter{00AB}{\guillemetleft} - \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot} - \DeclareUnicodeCharacter{00AD}{\-} - \DeclareUnicodeCharacter{00AE}{\registeredsymbol} - \DeclareUnicodeCharacter{00AF}{\={ }} - % - \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} - \DeclareUnicodeCharacter{00B1}{\ensuremath\pm} - \DeclareUnicodeCharacter{00B2}{$^2$} - \DeclareUnicodeCharacter{00B3}{$^3$} - \DeclareUnicodeCharacter{00B4}{\'{ }} - \DeclareUnicodeCharacter{00B5}{$\mu$} - \DeclareUnicodeCharacter{00B6}{\P} - \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot} - \DeclareUnicodeCharacter{00B8}{\cedilla{ }} - \DeclareUnicodeCharacter{00B9}{$^1$} - \DeclareUnicodeCharacter{00BA}{\ordm} - \DeclareUnicodeCharacter{00BB}{\guillemetright} - \DeclareUnicodeCharacter{00BC}{$1\over4$} - \DeclareUnicodeCharacter{00BD}{$1\over2$} - \DeclareUnicodeCharacter{00BE}{$3\over4$} - \DeclareUnicodeCharacter{00BF}{\questiondown} - % - \DeclareUnicodeCharacter{00C0}{\`A} - \DeclareUnicodeCharacter{00C1}{\'A} - \DeclareUnicodeCharacter{00C2}{\^A} - \DeclareUnicodeCharacter{00C3}{\~A} - \DeclareUnicodeCharacter{00C4}{\"A} - \DeclareUnicodeCharacter{00C5}{\AA} - \DeclareUnicodeCharacter{00C6}{\AE} - \DeclareUnicodeCharacter{00C7}{\cedilla{C}} - \DeclareUnicodeCharacter{00C8}{\`E} - \DeclareUnicodeCharacter{00C9}{\'E} - \DeclareUnicodeCharacter{00CA}{\^E} - \DeclareUnicodeCharacter{00CB}{\"E} - \DeclareUnicodeCharacter{00CC}{\`I} - \DeclareUnicodeCharacter{00CD}{\'I} - \DeclareUnicodeCharacter{00CE}{\^I} - \DeclareUnicodeCharacter{00CF}{\"I} - % - \DeclareUnicodeCharacter{00D0}{\DH} - \DeclareUnicodeCharacter{00D1}{\~N} - \DeclareUnicodeCharacter{00D2}{\`O} - \DeclareUnicodeCharacter{00D3}{\'O} - \DeclareUnicodeCharacter{00D4}{\^O} - \DeclareUnicodeCharacter{00D5}{\~O} - \DeclareUnicodeCharacter{00D6}{\"O} - \DeclareUnicodeCharacter{00D7}{\ensuremath\times} - \DeclareUnicodeCharacter{00D8}{\O} - \DeclareUnicodeCharacter{00D9}{\`U} - \DeclareUnicodeCharacter{00DA}{\'U} - \DeclareUnicodeCharacter{00DB}{\^U} - \DeclareUnicodeCharacter{00DC}{\"U} - \DeclareUnicodeCharacter{00DD}{\'Y} - \DeclareUnicodeCharacter{00DE}{\TH} - \DeclareUnicodeCharacter{00DF}{\ss} - % - \DeclareUnicodeCharacter{00E0}{\`a} - \DeclareUnicodeCharacter{00E1}{\'a} - \DeclareUnicodeCharacter{00E2}{\^a} - \DeclareUnicodeCharacter{00E3}{\~a} - \DeclareUnicodeCharacter{00E4}{\"a} - \DeclareUnicodeCharacter{00E5}{\aa} - \DeclareUnicodeCharacter{00E6}{\ae} - \DeclareUnicodeCharacter{00E7}{\cedilla{c}} - \DeclareUnicodeCharacter{00E8}{\`e} - \DeclareUnicodeCharacter{00E9}{\'e} - \DeclareUnicodeCharacter{00EA}{\^e} - \DeclareUnicodeCharacter{00EB}{\"e} - \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} - \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} - \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} - \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} - % - \DeclareUnicodeCharacter{00F0}{\dh} - \DeclareUnicodeCharacter{00F1}{\~n} - \DeclareUnicodeCharacter{00F2}{\`o} - \DeclareUnicodeCharacter{00F3}{\'o} - \DeclareUnicodeCharacter{00F4}{\^o} - \DeclareUnicodeCharacter{00F5}{\~o} - \DeclareUnicodeCharacter{00F6}{\"o} - \DeclareUnicodeCharacter{00F7}{\ensuremath\div} - \DeclareUnicodeCharacter{00F8}{\o} - \DeclareUnicodeCharacter{00F9}{\`u} - \DeclareUnicodeCharacter{00FA}{\'u} - \DeclareUnicodeCharacter{00FB}{\^u} - \DeclareUnicodeCharacter{00FC}{\"u} - \DeclareUnicodeCharacter{00FD}{\'y} - \DeclareUnicodeCharacter{00FE}{\th} - \DeclareUnicodeCharacter{00FF}{\"y} - % - \DeclareUnicodeCharacter{0100}{\=A} - \DeclareUnicodeCharacter{0101}{\=a} - \DeclareUnicodeCharacter{0102}{\u{A}} - \DeclareUnicodeCharacter{0103}{\u{a}} - \DeclareUnicodeCharacter{0104}{\ogonek{A}} - \DeclareUnicodeCharacter{0105}{\ogonek{a}} - \DeclareUnicodeCharacter{0106}{\'C} - \DeclareUnicodeCharacter{0107}{\'c} - \DeclareUnicodeCharacter{0108}{\^C} - \DeclareUnicodeCharacter{0109}{\^c} - \DeclareUnicodeCharacter{010A}{\dotaccent{C}} - \DeclareUnicodeCharacter{010B}{\dotaccent{c}} - \DeclareUnicodeCharacter{010C}{\v{C}} - \DeclareUnicodeCharacter{010D}{\v{c}} - \DeclareUnicodeCharacter{010E}{\v{D}} - \DeclareUnicodeCharacter{010F}{d'} - % - \DeclareUnicodeCharacter{0110}{\DH} - \DeclareUnicodeCharacter{0111}{\dh} - \DeclareUnicodeCharacter{0112}{\=E} - \DeclareUnicodeCharacter{0113}{\=e} - \DeclareUnicodeCharacter{0114}{\u{E}} - \DeclareUnicodeCharacter{0115}{\u{e}} - \DeclareUnicodeCharacter{0116}{\dotaccent{E}} - \DeclareUnicodeCharacter{0117}{\dotaccent{e}} - \DeclareUnicodeCharacter{0118}{\ogonek{E}} - \DeclareUnicodeCharacter{0119}{\ogonek{e}} - \DeclareUnicodeCharacter{011A}{\v{E}} - \DeclareUnicodeCharacter{011B}{\v{e}} - \DeclareUnicodeCharacter{011C}{\^G} - \DeclareUnicodeCharacter{011D}{\^g} - \DeclareUnicodeCharacter{011E}{\u{G}} - \DeclareUnicodeCharacter{011F}{\u{g}} - % - \DeclareUnicodeCharacter{0120}{\dotaccent{G}} - \DeclareUnicodeCharacter{0121}{\dotaccent{g}} - \DeclareUnicodeCharacter{0122}{\cedilla{G}} - \DeclareUnicodeCharacter{0123}{\cedilla{g}} - \DeclareUnicodeCharacter{0124}{\^H} - \DeclareUnicodeCharacter{0125}{\^h} - \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}} - \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}} - \DeclareUnicodeCharacter{0128}{\~I} - \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} - \DeclareUnicodeCharacter{012A}{\=I} - \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} - \DeclareUnicodeCharacter{012C}{\u{I}} - \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} - \DeclareUnicodeCharacter{012E}{\ogonek{I}} - \DeclareUnicodeCharacter{012F}{\ogonek{i}} - % - \DeclareUnicodeCharacter{0130}{\dotaccent{I}} - \DeclareUnicodeCharacter{0131}{\dotless{i}} - \DeclareUnicodeCharacter{0132}{IJ} - \DeclareUnicodeCharacter{0133}{ij} - \DeclareUnicodeCharacter{0134}{\^J} - \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} - \DeclareUnicodeCharacter{0136}{\cedilla{K}} - \DeclareUnicodeCharacter{0137}{\cedilla{k}} - \DeclareUnicodeCharacter{0138}{\ensuremath\kappa} - \DeclareUnicodeCharacter{0139}{\'L} - \DeclareUnicodeCharacter{013A}{\'l} - \DeclareUnicodeCharacter{013B}{\cedilla{L}} - \DeclareUnicodeCharacter{013C}{\cedilla{l}} + \DeclareUnicodeCharacter{00A7}{\S}% + \DeclareUnicodeCharacter{00A8}{\"{ }}% + \DeclareUnicodeCharacter{00A9}{\copyright{}}% + \DeclareUnicodeCharacter{00AA}{\ordf}% + \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}% + \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}% + \DeclareUnicodeCharacter{00AD}{\-}% + \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}% + \DeclareUnicodeCharacter{00AF}{\={ }}% + % + \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}% + \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}% + \DeclareUnicodeCharacter{00B2}{$^2$}% + \DeclareUnicodeCharacter{00B3}{$^3$}% + \DeclareUnicodeCharacter{00B4}{\'{ }}% + \DeclareUnicodeCharacter{00B5}{$\mu$}% + \DeclareUnicodeCharacter{00B6}{\P}% + \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}% + \DeclareUnicodeCharacter{00B8}{\cedilla{ }}% + \DeclareUnicodeCharacter{00B9}{$^1$}% + \DeclareUnicodeCharacter{00BA}{\ordm}% + \DeclareUnicodeCharacter{00BB}{\guillemetright{}}% + \DeclareUnicodeCharacter{00BC}{$1\over4$}% + \DeclareUnicodeCharacter{00BD}{$1\over2$}% + \DeclareUnicodeCharacter{00BE}{$3\over4$}% + \DeclareUnicodeCharacter{00BF}{\questiondown}% + % + \DeclareUnicodeCharacter{00C0}{\`A}% + \DeclareUnicodeCharacter{00C1}{\'A}% + \DeclareUnicodeCharacter{00C2}{\^A}% + \DeclareUnicodeCharacter{00C3}{\~A}% + \DeclareUnicodeCharacter{00C4}{\"A}% + \DeclareUnicodeCharacter{00C5}{\AA}% + \DeclareUnicodeCharacter{00C6}{\AE}% + \DeclareUnicodeCharacter{00C7}{\cedilla{C}}% + \DeclareUnicodeCharacter{00C8}{\`E}% + \DeclareUnicodeCharacter{00C9}{\'E}% + \DeclareUnicodeCharacter{00CA}{\^E}% + \DeclareUnicodeCharacter{00CB}{\"E}% + \DeclareUnicodeCharacter{00CC}{\`I}% + \DeclareUnicodeCharacter{00CD}{\'I}% + \DeclareUnicodeCharacter{00CE}{\^I}% + \DeclareUnicodeCharacter{00CF}{\"I}% + % + \DeclareUnicodeCharacter{00D0}{\DH}% + \DeclareUnicodeCharacter{00D1}{\~N}% + \DeclareUnicodeCharacter{00D2}{\`O}% + \DeclareUnicodeCharacter{00D3}{\'O}% + \DeclareUnicodeCharacter{00D4}{\^O}% + \DeclareUnicodeCharacter{00D5}{\~O}% + \DeclareUnicodeCharacter{00D6}{\"O}% + \DeclareUnicodeCharacter{00D7}{\ensuremath\times}% + \DeclareUnicodeCharacter{00D8}{\O}% + \DeclareUnicodeCharacter{00D9}{\`U}% + \DeclareUnicodeCharacter{00DA}{\'U}% + \DeclareUnicodeCharacter{00DB}{\^U}% + \DeclareUnicodeCharacter{00DC}{\"U}% + \DeclareUnicodeCharacter{00DD}{\'Y}% + \DeclareUnicodeCharacter{00DE}{\TH}% + \DeclareUnicodeCharacter{00DF}{\ss}% + % + \DeclareUnicodeCharacter{00E0}{\`a}% + \DeclareUnicodeCharacter{00E1}{\'a}% + \DeclareUnicodeCharacter{00E2}{\^a}% + \DeclareUnicodeCharacter{00E3}{\~a}% + \DeclareUnicodeCharacter{00E4}{\"a}% + \DeclareUnicodeCharacter{00E5}{\aa}% + \DeclareUnicodeCharacter{00E6}{\ae}% + \DeclareUnicodeCharacter{00E7}{\cedilla{c}}% + \DeclareUnicodeCharacter{00E8}{\`e}% + \DeclareUnicodeCharacter{00E9}{\'e}% + \DeclareUnicodeCharacter{00EA}{\^e}% + \DeclareUnicodeCharacter{00EB}{\"e}% + \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}% + \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}% + \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}% + \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}% + % + \DeclareUnicodeCharacter{00F0}{\dh}% + \DeclareUnicodeCharacter{00F1}{\~n}% + \DeclareUnicodeCharacter{00F2}{\`o}% + \DeclareUnicodeCharacter{00F3}{\'o}% + \DeclareUnicodeCharacter{00F4}{\^o}% + \DeclareUnicodeCharacter{00F5}{\~o}% + \DeclareUnicodeCharacter{00F6}{\"o}% + \DeclareUnicodeCharacter{00F7}{\ensuremath\div}% + \DeclareUnicodeCharacter{00F8}{\o}% + \DeclareUnicodeCharacter{00F9}{\`u}% + \DeclareUnicodeCharacter{00FA}{\'u}% + \DeclareUnicodeCharacter{00FB}{\^u}% + \DeclareUnicodeCharacter{00FC}{\"u}% + \DeclareUnicodeCharacter{00FD}{\'y}% + \DeclareUnicodeCharacter{00FE}{\th}% + \DeclareUnicodeCharacter{00FF}{\"y}% + % + \DeclareUnicodeCharacter{0100}{\=A}% + \DeclareUnicodeCharacter{0101}{\=a}% + \DeclareUnicodeCharacter{0102}{\u{A}}% + \DeclareUnicodeCharacter{0103}{\u{a}}% + \DeclareUnicodeCharacter{0104}{\ogonek{A}}% + \DeclareUnicodeCharacter{0105}{\ogonek{a}}% + \DeclareUnicodeCharacter{0106}{\'C}% + \DeclareUnicodeCharacter{0107}{\'c}% + \DeclareUnicodeCharacter{0108}{\^C}% + \DeclareUnicodeCharacter{0109}{\^c}% + \DeclareUnicodeCharacter{010A}{\dotaccent{C}}% + \DeclareUnicodeCharacter{010B}{\dotaccent{c}}% + \DeclareUnicodeCharacter{010C}{\v{C}}% + \DeclareUnicodeCharacter{010D}{\v{c}}% + \DeclareUnicodeCharacter{010E}{\v{D}}% + \DeclareUnicodeCharacter{010F}{d'}% + % + \DeclareUnicodeCharacter{0110}{\DH}% + \DeclareUnicodeCharacter{0111}{\dh}% + \DeclareUnicodeCharacter{0112}{\=E}% + \DeclareUnicodeCharacter{0113}{\=e}% + \DeclareUnicodeCharacter{0114}{\u{E}}% + \DeclareUnicodeCharacter{0115}{\u{e}}% + \DeclareUnicodeCharacter{0116}{\dotaccent{E}}% + \DeclareUnicodeCharacter{0117}{\dotaccent{e}}% + \DeclareUnicodeCharacter{0118}{\ogonek{E}}% + \DeclareUnicodeCharacter{0119}{\ogonek{e}}% + \DeclareUnicodeCharacter{011A}{\v{E}}% + \DeclareUnicodeCharacter{011B}{\v{e}}% + \DeclareUnicodeCharacter{011C}{\^G}% + \DeclareUnicodeCharacter{011D}{\^g}% + \DeclareUnicodeCharacter{011E}{\u{G}}% + \DeclareUnicodeCharacter{011F}{\u{g}}% + % + \DeclareUnicodeCharacter{0120}{\dotaccent{G}}% + \DeclareUnicodeCharacter{0121}{\dotaccent{g}}% + \DeclareUnicodeCharacter{0122}{\cedilla{G}}% + \DeclareUnicodeCharacter{0123}{\cedilla{g}}% + \DeclareUnicodeCharacter{0124}{\^H}% + \DeclareUnicodeCharacter{0125}{\^h}% + \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}% + \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}% + \DeclareUnicodeCharacter{0128}{\~I}% + \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}% + \DeclareUnicodeCharacter{012A}{\=I}% + \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}% + \DeclareUnicodeCharacter{012C}{\u{I}}% + \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}% + \DeclareUnicodeCharacter{012E}{\ogonek{I}}% + \DeclareUnicodeCharacter{012F}{\ogonek{i}}% + % + \DeclareUnicodeCharacter{0130}{\dotaccent{I}}% + \DeclareUnicodeCharacter{0131}{\dotless{i}}% + \DeclareUnicodeCharacter{0132}{IJ}% + \DeclareUnicodeCharacter{0133}{ij}% + \DeclareUnicodeCharacter{0134}{\^J}% + \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}% + \DeclareUnicodeCharacter{0136}{\cedilla{K}}% + \DeclareUnicodeCharacter{0137}{\cedilla{k}}% + \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}% + \DeclareUnicodeCharacter{0139}{\'L}% + \DeclareUnicodeCharacter{013A}{\'l}% + \DeclareUnicodeCharacter{013B}{\cedilla{L}}% + \DeclareUnicodeCharacter{013C}{\cedilla{l}}% \DeclareUnicodeCharacter{013D}{L'}% should kern \DeclareUnicodeCharacter{013E}{l'}% should kern - \DeclareUnicodeCharacter{013F}{L\U{00B7}} - % - \DeclareUnicodeCharacter{0140}{l\U{00B7}} - \DeclareUnicodeCharacter{0141}{\L} - \DeclareUnicodeCharacter{0142}{\l} - \DeclareUnicodeCharacter{0143}{\'N} - \DeclareUnicodeCharacter{0144}{\'n} - \DeclareUnicodeCharacter{0145}{\cedilla{N}} - \DeclareUnicodeCharacter{0146}{\cedilla{n}} - \DeclareUnicodeCharacter{0147}{\v{N}} - \DeclareUnicodeCharacter{0148}{\v{n}} - \DeclareUnicodeCharacter{0149}{'n} - \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}} - \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}} - \DeclareUnicodeCharacter{014C}{\=O} - \DeclareUnicodeCharacter{014D}{\=o} - \DeclareUnicodeCharacter{014E}{\u{O}} - \DeclareUnicodeCharacter{014F}{\u{o}} - % - \DeclareUnicodeCharacter{0150}{\H{O}} - \DeclareUnicodeCharacter{0151}{\H{o}} - \DeclareUnicodeCharacter{0152}{\OE} - \DeclareUnicodeCharacter{0153}{\oe} - \DeclareUnicodeCharacter{0154}{\'R} - \DeclareUnicodeCharacter{0155}{\'r} - \DeclareUnicodeCharacter{0156}{\cedilla{R}} - \DeclareUnicodeCharacter{0157}{\cedilla{r}} - \DeclareUnicodeCharacter{0158}{\v{R}} - \DeclareUnicodeCharacter{0159}{\v{r}} - \DeclareUnicodeCharacter{015A}{\'S} - \DeclareUnicodeCharacter{015B}{\'s} - \DeclareUnicodeCharacter{015C}{\^S} - \DeclareUnicodeCharacter{015D}{\^s} - \DeclareUnicodeCharacter{015E}{\cedilla{S}} - \DeclareUnicodeCharacter{015F}{\cedilla{s}} - % - \DeclareUnicodeCharacter{0160}{\v{S}} - \DeclareUnicodeCharacter{0161}{\v{s}} - \DeclareUnicodeCharacter{0162}{\cedilla{T}} - \DeclareUnicodeCharacter{0163}{\cedilla{t}} - \DeclareUnicodeCharacter{0164}{\v{T}} - \DeclareUnicodeCharacter{0165}{\v{t}} - \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}} - \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}} - \DeclareUnicodeCharacter{0168}{\~U} - \DeclareUnicodeCharacter{0169}{\~u} - \DeclareUnicodeCharacter{016A}{\=U} - \DeclareUnicodeCharacter{016B}{\=u} - \DeclareUnicodeCharacter{016C}{\u{U}} - \DeclareUnicodeCharacter{016D}{\u{u}} - \DeclareUnicodeCharacter{016E}{\ringaccent{U}} - \DeclareUnicodeCharacter{016F}{\ringaccent{u}} - % - \DeclareUnicodeCharacter{0170}{\H{U}} - \DeclareUnicodeCharacter{0171}{\H{u}} - \DeclareUnicodeCharacter{0172}{\ogonek{U}} - \DeclareUnicodeCharacter{0173}{\ogonek{u}} - \DeclareUnicodeCharacter{0174}{\^W} - \DeclareUnicodeCharacter{0175}{\^w} - \DeclareUnicodeCharacter{0176}{\^Y} - \DeclareUnicodeCharacter{0177}{\^y} - \DeclareUnicodeCharacter{0178}{\"Y} - \DeclareUnicodeCharacter{0179}{\'Z} - \DeclareUnicodeCharacter{017A}{\'z} - \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} - \DeclareUnicodeCharacter{017C}{\dotaccent{z}} - \DeclareUnicodeCharacter{017D}{\v{Z}} - \DeclareUnicodeCharacter{017E}{\v{z}} - \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}} - % - \DeclareUnicodeCharacter{01C4}{D\v{Z}} - \DeclareUnicodeCharacter{01C5}{D\v{z}} - \DeclareUnicodeCharacter{01C6}{d\v{z}} - \DeclareUnicodeCharacter{01C7}{LJ} - \DeclareUnicodeCharacter{01C8}{Lj} - \DeclareUnicodeCharacter{01C9}{lj} - \DeclareUnicodeCharacter{01CA}{NJ} - \DeclareUnicodeCharacter{01CB}{Nj} - \DeclareUnicodeCharacter{01CC}{nj} - \DeclareUnicodeCharacter{01CD}{\v{A}} - \DeclareUnicodeCharacter{01CE}{\v{a}} - \DeclareUnicodeCharacter{01CF}{\v{I}} - % - \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} - \DeclareUnicodeCharacter{01D1}{\v{O}} - \DeclareUnicodeCharacter{01D2}{\v{o}} - \DeclareUnicodeCharacter{01D3}{\v{U}} - \DeclareUnicodeCharacter{01D4}{\v{u}} - % - \DeclareUnicodeCharacter{01E2}{\={\AE}} - \DeclareUnicodeCharacter{01E3}{\={\ae}} - \DeclareUnicodeCharacter{01E6}{\v{G}} - \DeclareUnicodeCharacter{01E7}{\v{g}} - \DeclareUnicodeCharacter{01E8}{\v{K}} - \DeclareUnicodeCharacter{01E9}{\v{k}} - % - \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} - \DeclareUnicodeCharacter{01F1}{DZ} - \DeclareUnicodeCharacter{01F2}{Dz} - \DeclareUnicodeCharacter{01F3}{dz} - \DeclareUnicodeCharacter{01F4}{\'G} - \DeclareUnicodeCharacter{01F5}{\'g} - \DeclareUnicodeCharacter{01F8}{\`N} - \DeclareUnicodeCharacter{01F9}{\`n} - \DeclareUnicodeCharacter{01FC}{\'{\AE}} - \DeclareUnicodeCharacter{01FD}{\'{\ae}} - \DeclareUnicodeCharacter{01FE}{\'{\O}} - \DeclareUnicodeCharacter{01FF}{\'{\o}} - % - \DeclareUnicodeCharacter{021E}{\v{H}} - \DeclareUnicodeCharacter{021F}{\v{h}} - % - \DeclareUnicodeCharacter{0226}{\dotaccent{A}} - \DeclareUnicodeCharacter{0227}{\dotaccent{a}} - \DeclareUnicodeCharacter{0228}{\cedilla{E}} - \DeclareUnicodeCharacter{0229}{\cedilla{e}} - \DeclareUnicodeCharacter{022E}{\dotaccent{O}} - \DeclareUnicodeCharacter{022F}{\dotaccent{o}} - % - \DeclareUnicodeCharacter{0232}{\=Y} - \DeclareUnicodeCharacter{0233}{\=y} - \DeclareUnicodeCharacter{0237}{\dotless{j}} - % - \DeclareUnicodeCharacter{02DB}{\ogonek{ }} + \DeclareUnicodeCharacter{013F}{L\U{00B7}}% + % + \DeclareUnicodeCharacter{0140}{l\U{00B7}}% + \DeclareUnicodeCharacter{0141}{\L}% + \DeclareUnicodeCharacter{0142}{\l}% + \DeclareUnicodeCharacter{0143}{\'N}% + \DeclareUnicodeCharacter{0144}{\'n}% + \DeclareUnicodeCharacter{0145}{\cedilla{N}}% + \DeclareUnicodeCharacter{0146}{\cedilla{n}}% + \DeclareUnicodeCharacter{0147}{\v{N}}% + \DeclareUnicodeCharacter{0148}{\v{n}}% + \DeclareUnicodeCharacter{0149}{'n}% + \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}% + \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}% + \DeclareUnicodeCharacter{014C}{\=O}% + \DeclareUnicodeCharacter{014D}{\=o}% + \DeclareUnicodeCharacter{014E}{\u{O}}% + \DeclareUnicodeCharacter{014F}{\u{o}}% + % + \DeclareUnicodeCharacter{0150}{\H{O}}% + \DeclareUnicodeCharacter{0151}{\H{o}}% + \DeclareUnicodeCharacter{0152}{\OE}% + \DeclareUnicodeCharacter{0153}{\oe}% + \DeclareUnicodeCharacter{0154}{\'R}% + \DeclareUnicodeCharacter{0155}{\'r}% + \DeclareUnicodeCharacter{0156}{\cedilla{R}}% + \DeclareUnicodeCharacter{0157}{\cedilla{r}}% + \DeclareUnicodeCharacter{0158}{\v{R}}% + \DeclareUnicodeCharacter{0159}{\v{r}}% + \DeclareUnicodeCharacter{015A}{\'S}% + \DeclareUnicodeCharacter{015B}{\'s}% + \DeclareUnicodeCharacter{015C}{\^S}% + \DeclareUnicodeCharacter{015D}{\^s}% + \DeclareUnicodeCharacter{015E}{\cedilla{S}}% + \DeclareUnicodeCharacter{015F}{\cedilla{s}}% + % + \DeclareUnicodeCharacter{0160}{\v{S}}% + \DeclareUnicodeCharacter{0161}{\v{s}}% + \DeclareUnicodeCharacter{0162}{\cedilla{T}}% + \DeclareUnicodeCharacter{0163}{\cedilla{t}}% + \DeclareUnicodeCharacter{0164}{\v{T}}% + \DeclareUnicodeCharacter{0165}{\v{t}}% + \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}% + \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}% + \DeclareUnicodeCharacter{0168}{\~U}% + \DeclareUnicodeCharacter{0169}{\~u}% + \DeclareUnicodeCharacter{016A}{\=U}% + \DeclareUnicodeCharacter{016B}{\=u}% + \DeclareUnicodeCharacter{016C}{\u{U}}% + \DeclareUnicodeCharacter{016D}{\u{u}}% + \DeclareUnicodeCharacter{016E}{\ringaccent{U}}% + \DeclareUnicodeCharacter{016F}{\ringaccent{u}}% + % + \DeclareUnicodeCharacter{0170}{\H{U}}% + \DeclareUnicodeCharacter{0171}{\H{u}}% + \DeclareUnicodeCharacter{0172}{\ogonek{U}}% + \DeclareUnicodeCharacter{0173}{\ogonek{u}}% + \DeclareUnicodeCharacter{0174}{\^W}% + \DeclareUnicodeCharacter{0175}{\^w}% + \DeclareUnicodeCharacter{0176}{\^Y}% + \DeclareUnicodeCharacter{0177}{\^y}% + \DeclareUnicodeCharacter{0178}{\"Y}% + \DeclareUnicodeCharacter{0179}{\'Z}% + \DeclareUnicodeCharacter{017A}{\'z}% + \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}% + \DeclareUnicodeCharacter{017C}{\dotaccent{z}}% + \DeclareUnicodeCharacter{017D}{\v{Z}}% + \DeclareUnicodeCharacter{017E}{\v{z}}% + \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}% + % + \DeclareUnicodeCharacter{01C4}{D\v{Z}}% + \DeclareUnicodeCharacter{01C5}{D\v{z}}% + \DeclareUnicodeCharacter{01C6}{d\v{z}}% + \DeclareUnicodeCharacter{01C7}{LJ}% + \DeclareUnicodeCharacter{01C8}{Lj}% + \DeclareUnicodeCharacter{01C9}{lj}% + \DeclareUnicodeCharacter{01CA}{NJ}% + \DeclareUnicodeCharacter{01CB}{Nj}% + \DeclareUnicodeCharacter{01CC}{nj}% + \DeclareUnicodeCharacter{01CD}{\v{A}}% + \DeclareUnicodeCharacter{01CE}{\v{a}}% + \DeclareUnicodeCharacter{01CF}{\v{I}}% + % + \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}% + \DeclareUnicodeCharacter{01D1}{\v{O}}% + \DeclareUnicodeCharacter{01D2}{\v{o}}% + \DeclareUnicodeCharacter{01D3}{\v{U}}% + \DeclareUnicodeCharacter{01D4}{\v{u}}% + % + \DeclareUnicodeCharacter{01E2}{\={\AE}}% + \DeclareUnicodeCharacter{01E3}{\={\ae}}% + \DeclareUnicodeCharacter{01E6}{\v{G}}% + \DeclareUnicodeCharacter{01E7}{\v{g}}% + \DeclareUnicodeCharacter{01E8}{\v{K}}% + \DeclareUnicodeCharacter{01E9}{\v{k}}% + % + \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}% + \DeclareUnicodeCharacter{01F1}{DZ}% + \DeclareUnicodeCharacter{01F2}{Dz}% + \DeclareUnicodeCharacter{01F3}{dz}% + \DeclareUnicodeCharacter{01F4}{\'G}% + \DeclareUnicodeCharacter{01F5}{\'g}% + \DeclareUnicodeCharacter{01F8}{\`N}% + \DeclareUnicodeCharacter{01F9}{\`n}% + \DeclareUnicodeCharacter{01FC}{\'{\AE}}% + \DeclareUnicodeCharacter{01FD}{\'{\ae}}% + \DeclareUnicodeCharacter{01FE}{\'{\O}}% + \DeclareUnicodeCharacter{01FF}{\'{\o}}% + % + \DeclareUnicodeCharacter{021E}{\v{H}}% + \DeclareUnicodeCharacter{021F}{\v{h}}% + % + \DeclareUnicodeCharacter{0226}{\dotaccent{A}}% + \DeclareUnicodeCharacter{0227}{\dotaccent{a}}% + \DeclareUnicodeCharacter{0228}{\cedilla{E}}% + \DeclareUnicodeCharacter{0229}{\cedilla{e}}% + \DeclareUnicodeCharacter{022E}{\dotaccent{O}}% + \DeclareUnicodeCharacter{022F}{\dotaccent{o}}% + % + \DeclareUnicodeCharacter{0232}{\=Y}% + \DeclareUnicodeCharacter{0233}{\=y}% + \DeclareUnicodeCharacter{0237}{\dotless{j}}% + % + \DeclareUnicodeCharacter{02DB}{\ogonek{ }}% % % Greek letters upper case - \DeclareUnicodeCharacter{0391}{{\it A}} - \DeclareUnicodeCharacter{0392}{{\it B}} - \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}} - \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}} - \DeclareUnicodeCharacter{0395}{{\it E}} - \DeclareUnicodeCharacter{0396}{{\it Z}} - \DeclareUnicodeCharacter{0397}{{\it H}} - \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}} - \DeclareUnicodeCharacter{0399}{{\it I}} - \DeclareUnicodeCharacter{039A}{{\it K}} - \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}} - \DeclareUnicodeCharacter{039C}{{\it M}} - \DeclareUnicodeCharacter{039D}{{\it N}} - \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}} - \DeclareUnicodeCharacter{039F}{{\it O}} - \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}} - \DeclareUnicodeCharacter{03A1}{{\it P}} + \DeclareUnicodeCharacter{0391}{{\it A}}% + \DeclareUnicodeCharacter{0392}{{\it B}}% + \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}% + \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}% + \DeclareUnicodeCharacter{0395}{{\it E}}% + \DeclareUnicodeCharacter{0396}{{\it Z}}% + \DeclareUnicodeCharacter{0397}{{\it H}}% + \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}% + \DeclareUnicodeCharacter{0399}{{\it I}}% + \DeclareUnicodeCharacter{039A}{{\it K}}% + \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}% + \DeclareUnicodeCharacter{039C}{{\it M}}% + \DeclareUnicodeCharacter{039D}{{\it N}}% + \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}% + \DeclareUnicodeCharacter{039F}{{\it O}}% + \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}% + \DeclareUnicodeCharacter{03A1}{{\it P}}% %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma - \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}} - \DeclareUnicodeCharacter{03A4}{{\it T}} - \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}} - \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}} - \DeclareUnicodeCharacter{03A7}{{\it X}} - \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}} - \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}} + \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}% + \DeclareUnicodeCharacter{03A4}{{\it T}}% + \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}% + \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}% + \DeclareUnicodeCharacter{03A7}{{\it X}}% + \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}% + \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}% % % Vowels with accents - \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}} - \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}} - \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}} - \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}} - \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}} - \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}} + \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}% + \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}% + \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}% + \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}% + \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}% + \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}% % % Standalone accent - \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}} + \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}% % % Greek letters lower case - \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha} - \DeclareUnicodeCharacter{03B2}{\ensuremath\beta} - \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma} - \DeclareUnicodeCharacter{03B4}{\ensuremath\delta} - \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon} - \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta} - \DeclareUnicodeCharacter{03B7}{\ensuremath\eta} - \DeclareUnicodeCharacter{03B8}{\ensuremath\theta} - \DeclareUnicodeCharacter{03B9}{\ensuremath\iota} - \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa} - \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda} - \DeclareUnicodeCharacter{03BC}{\ensuremath\mu} - \DeclareUnicodeCharacter{03BD}{\ensuremath\nu} - \DeclareUnicodeCharacter{03BE}{\ensuremath\xi} - \DeclareUnicodeCharacter{03BF}{{\it o}} % omicron - \DeclareUnicodeCharacter{03C0}{\ensuremath\pi} - \DeclareUnicodeCharacter{03C1}{\ensuremath\rho} - \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma} - \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma} - \DeclareUnicodeCharacter{03C4}{\ensuremath\tau} - \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon} - \DeclareUnicodeCharacter{03C6}{\ensuremath\phi} - \DeclareUnicodeCharacter{03C7}{\ensuremath\chi} - \DeclareUnicodeCharacter{03C8}{\ensuremath\psi} - \DeclareUnicodeCharacter{03C9}{\ensuremath\omega} + \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}% + \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}% + \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}% + \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}% + \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}% + \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}% + \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}% + \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}% + \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}% + \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}% + \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}% + \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}% + \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}% + \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}% + \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron + \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}% + \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}% + \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}% + \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}% + \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}% + \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}% + \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}% + \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}% + \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}% + \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}% % % More Greek vowels with accents - \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}} - \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}} - \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}} - \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}} - \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}} + \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}% + \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}% + \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}% + \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}% + \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}% % % Variant Greek letters - \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta} - \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi} - \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho} - % - \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} - \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} - \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} - \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} - \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} - \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} - \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} - \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} - \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} - \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} - \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} - \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} - % - \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} - \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} - % - \DeclareUnicodeCharacter{1E20}{\=G} - \DeclareUnicodeCharacter{1E21}{\=g} - \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} - \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} - \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} - \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} - \DeclareUnicodeCharacter{1E26}{\"H} - \DeclareUnicodeCharacter{1E27}{\"h} - % - \DeclareUnicodeCharacter{1E30}{\'K} - \DeclareUnicodeCharacter{1E31}{\'k} - \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} - \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} - \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} - \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} - \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} - \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} - \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} - \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} - \DeclareUnicodeCharacter{1E3E}{\'M} - \DeclareUnicodeCharacter{1E3F}{\'m} - % - \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} - \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} - \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} - \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} - \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} - \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} - \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} - \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} - \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} - \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} - % - \DeclareUnicodeCharacter{1E54}{\'P} - \DeclareUnicodeCharacter{1E55}{\'p} - \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} - \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} - \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} - \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} - \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} - \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} - \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} - \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} - % - \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} - \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} - \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} - \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} - \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} - \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} - \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} - \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} - \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} - \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} - % - \DeclareUnicodeCharacter{1E7C}{\~V} - \DeclareUnicodeCharacter{1E7D}{\~v} - \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} - \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} - % - \DeclareUnicodeCharacter{1E80}{\`W} - \DeclareUnicodeCharacter{1E81}{\`w} - \DeclareUnicodeCharacter{1E82}{\'W} - \DeclareUnicodeCharacter{1E83}{\'w} - \DeclareUnicodeCharacter{1E84}{\"W} - \DeclareUnicodeCharacter{1E85}{\"w} - \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} - \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} - \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} - \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} - \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} - \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} - \DeclareUnicodeCharacter{1E8C}{\"X} - \DeclareUnicodeCharacter{1E8D}{\"x} - \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} - \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} - % - \DeclareUnicodeCharacter{1E90}{\^Z} - \DeclareUnicodeCharacter{1E91}{\^z} - \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} - \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} - \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} - \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} - \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} - \DeclareUnicodeCharacter{1E97}{\"t} - \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} - \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} - % - \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} - \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} - % - \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} - \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} - \DeclareUnicodeCharacter{1EBC}{\~E} - \DeclareUnicodeCharacter{1EBD}{\~e} - % - \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} - \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} - \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} - \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} - % - \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} - \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} - % - \DeclareUnicodeCharacter{1EF2}{\`Y} - \DeclareUnicodeCharacter{1EF3}{\`y} - \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} - % - \DeclareUnicodeCharacter{1EF8}{\~Y} - \DeclareUnicodeCharacter{1EF9}{\~y} + \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}% + \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}% + \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}% + % + \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}% + \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}% + \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}% + \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}% + \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}% + \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}% + \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}% + \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}% + \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}% + \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}% + \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}% + \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}% + % + \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}% + \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}% + % + \DeclareUnicodeCharacter{1E20}{\=G}% + \DeclareUnicodeCharacter{1E21}{\=g}% + \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}% + \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}% + \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}% + \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}% + \DeclareUnicodeCharacter{1E26}{\"H}% + \DeclareUnicodeCharacter{1E27}{\"h}% + % + \DeclareUnicodeCharacter{1E30}{\'K}% + \DeclareUnicodeCharacter{1E31}{\'k}% + \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}% + \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}% + \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}% + \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}% + \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}% + \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}% + \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}% + \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}% + \DeclareUnicodeCharacter{1E3E}{\'M}% + \DeclareUnicodeCharacter{1E3F}{\'m}% + % + \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}% + \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}% + \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}% + \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}% + \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}% + \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}% + \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}% + \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}% + \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}% + \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}% + % + \DeclareUnicodeCharacter{1E54}{\'P}% + \DeclareUnicodeCharacter{1E55}{\'p}% + \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}% + \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}% + \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}% + \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}% + \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}% + \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}% + \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}% + \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}% + % + \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}% + \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}% + \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}% + \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}% + \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}% + \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}% + \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}% + \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}% + \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}% + \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}% + % + \DeclareUnicodeCharacter{1E7C}{\~V}% + \DeclareUnicodeCharacter{1E7D}{\~v}% + \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}% + \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}% + % + \DeclareUnicodeCharacter{1E80}{\`W}% + \DeclareUnicodeCharacter{1E81}{\`w}% + \DeclareUnicodeCharacter{1E82}{\'W}% + \DeclareUnicodeCharacter{1E83}{\'w}% + \DeclareUnicodeCharacter{1E84}{\"W}% + \DeclareUnicodeCharacter{1E85}{\"w}% + \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}% + \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}% + \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}% + \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}% + \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}% + \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}% + \DeclareUnicodeCharacter{1E8C}{\"X}% + \DeclareUnicodeCharacter{1E8D}{\"x}% + \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}% + \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}% + % + \DeclareUnicodeCharacter{1E90}{\^Z}% + \DeclareUnicodeCharacter{1E91}{\^z}% + \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}% + \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}% + \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}% + \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}% + \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}% + \DeclareUnicodeCharacter{1E97}{\"t}% + \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}% + \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}% + % + \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}% + \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}% + % + \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}% + \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}% + \DeclareUnicodeCharacter{1EBC}{\~E}% + \DeclareUnicodeCharacter{1EBD}{\~e}% + % + \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}% + \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}% + \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}% + \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}% + % + \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}% + \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}% + % + \DeclareUnicodeCharacter{1EF2}{\`Y}% + \DeclareUnicodeCharacter{1EF3}{\`y}% + \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}% + % + \DeclareUnicodeCharacter{1EF8}{\~Y}% + \DeclareUnicodeCharacter{1EF9}{\~y}% % % Punctuation - \DeclareUnicodeCharacter{2013}{--} - \DeclareUnicodeCharacter{2014}{---} - \DeclareUnicodeCharacter{2018}{\quoteleft} - \DeclareUnicodeCharacter{2019}{\quoteright} - \DeclareUnicodeCharacter{201A}{\quotesinglbase} - \DeclareUnicodeCharacter{201C}{\quotedblleft} - \DeclareUnicodeCharacter{201D}{\quotedblright} - \DeclareUnicodeCharacter{201E}{\quotedblbase} - \DeclareUnicodeCharacter{2020}{\ensuremath\dagger} - \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger} - \DeclareUnicodeCharacter{2022}{\bullet} - \DeclareUnicodeCharacter{202F}{\thinspace} - \DeclareUnicodeCharacter{2026}{\dots} - \DeclareUnicodeCharacter{2039}{\guilsinglleft} - \DeclareUnicodeCharacter{203A}{\guilsinglright} - % - \DeclareUnicodeCharacter{20AC}{\euro} - % - \DeclareUnicodeCharacter{2192}{\expansion} - \DeclareUnicodeCharacter{21D2}{\result} + \DeclareUnicodeCharacter{2013}{--}% + \DeclareUnicodeCharacter{2014}{---}% + \DeclareUnicodeCharacter{2018}{\quoteleft{}}% + \DeclareUnicodeCharacter{2019}{\quoteright{}}% + \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}% + \DeclareUnicodeCharacter{201C}{\quotedblleft{}}% + \DeclareUnicodeCharacter{201D}{\quotedblright{}}% + \DeclareUnicodeCharacter{201E}{\quotedblbase{}}% + \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}% + \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}% + \DeclareUnicodeCharacter{2022}{\bullet{}}% + \DeclareUnicodeCharacter{202F}{\thinspace}% + \DeclareUnicodeCharacter{2026}{\dots{}}% + \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}% + \DeclareUnicodeCharacter{203A}{\guilsinglright{}}% + % + \DeclareUnicodeCharacter{20AC}{\euro{}}% + % + \DeclareUnicodeCharacter{2192}{\expansion{}}% + \DeclareUnicodeCharacter{21D2}{\result{}}% % % Mathematical symbols - \DeclareUnicodeCharacter{2200}{\ensuremath\forall} - \DeclareUnicodeCharacter{2203}{\ensuremath\exists} - \DeclareUnicodeCharacter{2208}{\ensuremath\in} - \DeclareUnicodeCharacter{2212}{\minus} - \DeclareUnicodeCharacter{2217}{\ast} - \DeclareUnicodeCharacter{221E}{\ensuremath\infty} - \DeclareUnicodeCharacter{2225}{\ensuremath\parallel} - \DeclareUnicodeCharacter{2227}{\ensuremath\wedge} - \DeclareUnicodeCharacter{2229}{\ensuremath\cap} - \DeclareUnicodeCharacter{2261}{\equiv} - \DeclareUnicodeCharacter{2264}{\ensuremath\leq} - \DeclareUnicodeCharacter{2265}{\ensuremath\geq} - \DeclareUnicodeCharacter{2282}{\ensuremath\subset} - \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq} - % - \DeclareUnicodeCharacter{2016}{\ensuremath\Vert} - \DeclareUnicodeCharacter{2032}{\ensuremath\prime} - \DeclareUnicodeCharacter{210F}{\ensuremath\hbar} - \DeclareUnicodeCharacter{2111}{\ensuremath\Im} - \DeclareUnicodeCharacter{2113}{\ensuremath\ell} - \DeclareUnicodeCharacter{2118}{\ensuremath\wp} - \DeclareUnicodeCharacter{211C}{\ensuremath\Re} - \DeclareUnicodeCharacter{2127}{\ensuremath\mho} - \DeclareUnicodeCharacter{2135}{\ensuremath\aleph} - \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow} - \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow} - \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow} - \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow} - \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow} - \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow} - \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow} - \DeclareUnicodeCharacter{2198}{\ensuremath\searrow} - \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow} - \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto} - \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow} - \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow} - \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup} - \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown} - \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright} - \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup} - \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown} - \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons} - \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow} - \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow} - \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow} - \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow} - \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow} - \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto} - \DeclareUnicodeCharacter{2201}{\ensuremath\complement} - \DeclareUnicodeCharacter{2202}{\ensuremath\partial} - \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset} - \DeclareUnicodeCharacter{2207}{\ensuremath\nabla} - \DeclareUnicodeCharacter{2209}{\ensuremath\notin} - \DeclareUnicodeCharacter{220B}{\ensuremath\owns} - \DeclareUnicodeCharacter{220F}{\ensuremath\prod} - \DeclareUnicodeCharacter{2210}{\ensuremath\coprod} - \DeclareUnicodeCharacter{2211}{\ensuremath\sum} - \DeclareUnicodeCharacter{2213}{\ensuremath\mp} - \DeclareUnicodeCharacter{2218}{\ensuremath\circ} - \DeclareUnicodeCharacter{221A}{\ensuremath\surd} - \DeclareUnicodeCharacter{221D}{\ensuremath\propto} - \DeclareUnicodeCharacter{2220}{\ensuremath\angle} - \DeclareUnicodeCharacter{2223}{\ensuremath\mid} - \DeclareUnicodeCharacter{2228}{\ensuremath\vee} - \DeclareUnicodeCharacter{222A}{\ensuremath\cup} - \DeclareUnicodeCharacter{222B}{\ensuremath\smallint} - \DeclareUnicodeCharacter{222E}{\ensuremath\oint} - \DeclareUnicodeCharacter{223C}{\ensuremath\sim} - \DeclareUnicodeCharacter{2240}{\ensuremath\wr} - \DeclareUnicodeCharacter{2243}{\ensuremath\simeq} - \DeclareUnicodeCharacter{2245}{\ensuremath\cong} - \DeclareUnicodeCharacter{2248}{\ensuremath\approx} - \DeclareUnicodeCharacter{224D}{\ensuremath\asymp} - \DeclareUnicodeCharacter{2250}{\ensuremath\doteq} - \DeclareUnicodeCharacter{2260}{\ensuremath\neq} - \DeclareUnicodeCharacter{226A}{\ensuremath\ll} - \DeclareUnicodeCharacter{226B}{\ensuremath\gg} - \DeclareUnicodeCharacter{227A}{\ensuremath\prec} - \DeclareUnicodeCharacter{227B}{\ensuremath\succ} - \DeclareUnicodeCharacter{2283}{\ensuremath\supset} - \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq} - \DeclareUnicodeCharacter{228E}{\ensuremath\uplus} - \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset} - \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset} - \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq} - \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq} - \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap} - \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup} - \DeclareUnicodeCharacter{2295}{\ensuremath\oplus} - \DeclareUnicodeCharacter{2296}{\ensuremath\ominus} - \DeclareUnicodeCharacter{2297}{\ensuremath\otimes} - \DeclareUnicodeCharacter{2298}{\ensuremath\oslash} - \DeclareUnicodeCharacter{2299}{\ensuremath\odot} - \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash} - \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv} - \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop} - \DeclareUnicodeCharacter{22A5}{\ensuremath\bot} - \DeclareUnicodeCharacter{22A8}{\ensuremath\models} - \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd} - \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd} - \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge} - \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee} - \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap} - \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup} - \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond} - \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot} - \DeclareUnicodeCharacter{22C6}{\ensuremath\star} - \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie} - \DeclareUnicodeCharacter{2308}{\ensuremath\lceil} - \DeclareUnicodeCharacter{2309}{\ensuremath\rceil} - \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor} - \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor} - \DeclareUnicodeCharacter{2322}{\ensuremath\frown} - \DeclareUnicodeCharacter{2323}{\ensuremath\smile} - % - \DeclareUnicodeCharacter{25A1}{\ensuremath\Box} - \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle} - \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright} - \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown} - \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft} - \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond} - \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit} - \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit} - \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit} - \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit} - \DeclareUnicodeCharacter{266D}{\ensuremath\flat} - \DeclareUnicodeCharacter{266E}{\ensuremath\natural} - \DeclareUnicodeCharacter{266F}{\ensuremath\sharp} - \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc} - \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle} - \DeclareUnicodeCharacter{27C2}{\ensuremath\perp} - \DeclareUnicodeCharacter{27E8}{\ensuremath\langle} - \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow} - \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow} - \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow} - \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto} - \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus} - \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot} - \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus} - \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes} - \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus} - \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup} - \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join} - \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg} - \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq} - \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq} - % - \global\mathchardef\checkmark="1370 % actually the square root sign - \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark} -}% end of \utfeightchardefs + \DeclareUnicodeCharacter{2200}{\ensuremath\forall}% + \DeclareUnicodeCharacter{2203}{\ensuremath\exists}% + \DeclareUnicodeCharacter{2208}{\ensuremath\in}% + \DeclareUnicodeCharacter{2212}{\minus{}}% + \DeclareUnicodeCharacter{2217}{\ast}% + \DeclareUnicodeCharacter{221E}{\ensuremath\infty}% + \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}% + \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}% + \DeclareUnicodeCharacter{2229}{\ensuremath\cap}% + \DeclareUnicodeCharacter{2261}{\equiv{}}% + \DeclareUnicodeCharacter{2264}{\ensuremath\leq}% + \DeclareUnicodeCharacter{2265}{\ensuremath\geq}% + \DeclareUnicodeCharacter{2282}{\ensuremath\subset}% + \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}% + % + \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}% + \DeclareUnicodeCharacter{2032}{\ensuremath\prime}% + \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}% + \DeclareUnicodeCharacter{2111}{\ensuremath\Im}% + \DeclareUnicodeCharacter{2113}{\ensuremath\ell}% + \DeclareUnicodeCharacter{2118}{\ensuremath\wp}% + \DeclareUnicodeCharacter{211C}{\ensuremath\Re}% + \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}% + \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}% + \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}% + \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}% + \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}% + \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}% + \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}% + \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}% + \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}% + \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}% + \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}% + \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}% + \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}% + \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}% + \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}% + \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}% + \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}% + \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}% + \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}% + \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}% + \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}% + \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}% + \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}% + \DeclareUnicodeCharacter{2202}{\ensuremath\partial}% + \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}% + \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}% + \DeclareUnicodeCharacter{2209}{\ensuremath\notin}% + \DeclareUnicodeCharacter{220B}{\ensuremath\owns}% + \DeclareUnicodeCharacter{220F}{\ensuremath\prod}% + \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}% + \DeclareUnicodeCharacter{2211}{\ensuremath\sum}% + \DeclareUnicodeCharacter{2213}{\ensuremath\mp}% + \DeclareUnicodeCharacter{2218}{\ensuremath\circ}% + \DeclareUnicodeCharacter{221A}{\ensuremath\surd}% + \DeclareUnicodeCharacter{221D}{\ensuremath\propto}% + \DeclareUnicodeCharacter{2220}{\ensuremath\angle}% + \DeclareUnicodeCharacter{2223}{\ensuremath\mid}% + \DeclareUnicodeCharacter{2228}{\ensuremath\vee}% + \DeclareUnicodeCharacter{222A}{\ensuremath\cup}% + \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}% + \DeclareUnicodeCharacter{222E}{\ensuremath\oint}% + \DeclareUnicodeCharacter{223C}{\ensuremath\sim}% + \DeclareUnicodeCharacter{2240}{\ensuremath\wr}% + \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}% + \DeclareUnicodeCharacter{2245}{\ensuremath\cong}% + \DeclareUnicodeCharacter{2248}{\ensuremath\approx}% + \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}% + \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}% + \DeclareUnicodeCharacter{2260}{\ensuremath\neq}% + \DeclareUnicodeCharacter{226A}{\ensuremath\ll}% + \DeclareUnicodeCharacter{226B}{\ensuremath\gg}% + \DeclareUnicodeCharacter{227A}{\ensuremath\prec}% + \DeclareUnicodeCharacter{227B}{\ensuremath\succ}% + \DeclareUnicodeCharacter{2283}{\ensuremath\supset}% + \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}% + \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}% + \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}% + \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}% + \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}% + \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}% + \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}% + \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}% + \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}% + \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}% + \DeclareUnicodeCharacter{2299}{\ensuremath\odot}% + \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}% + \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}% + \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}% + \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}% + \DeclareUnicodeCharacter{22A8}{\ensuremath\models}% + \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}% + \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}% + \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}% + \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}% + \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}% + \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}% + \DeclareUnicodeCharacter{22C6}{\ensuremath\star}% + \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}% + \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}% + \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}% + \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}% + \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}% + \DeclareUnicodeCharacter{2322}{\ensuremath\frown}% + \DeclareUnicodeCharacter{2323}{\ensuremath\smile}% + % + \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}% + \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}% + \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}% + \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}% + \DeclareUnicodeCharacter{25C7}{\ensuremath\diamond}% + \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}% + \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}% + \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}% + \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}% + \DeclareUnicodeCharacter{266D}{\ensuremath\flat}% + \DeclareUnicodeCharacter{266E}{\ensuremath\natural}% + \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}% + \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}% + \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}% + \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}% + \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}% + \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}% + \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}% + \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}% + \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}% + \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}% + \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}% + \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}% + \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}% + \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}% + \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}% + \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}% + \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}% + \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}% + % + \global\mathchardef\checkmark="1370% actually the square root sign + \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}% +}% end of \unicodechardefs + +% UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command) +% It makes the setting that replace UTF-8 byte sequence. +\def\utfeightchardefs{% + \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii + \unicodechardefs +} -% US-ASCII character definitions. -\def\asciichardefs{% nothing need be done - \relax +% Whether the active definitions of non-ASCII characters expand to +% non-active tokens with the same character code. This is used to +% write characters literally, instead of using active definitions for +% printing the correct glyphs. +\newif\ifpassthroughchars +\passthroughcharsfalse + +% For native Unicode handling (XeTeX and LuaTeX), +% provide a definition macro to replace/pass-through a Unicode character +% +\def\DeclareUnicodeCharacterNative#1#2{% + \catcode"#1=\active + \def\dodeclareunicodecharacternative##1##2##3{% + \begingroup + \uccode`\~="##2\relax + \uppercase{\gdef~}{% + \ifpassthroughchars + ##1% + \else + ##3% + \fi + } + \endgroup + } + \begingroup + \uccode`\.="#1\relax + \uppercase{\def\UTFNativeTmp{.}}% + \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}% + \endgroup } -% Latin1 (ISO-8859-1) character definitions. -\def\nonasciistringdefs{% - \setnonasciicharscatcode\active - \def\defstringchar##1{\def##1{\string##1}}% - % - \defstringchar^^80\defstringchar^^81\defstringchar^^82\defstringchar^^83% - \defstringchar^^84\defstringchar^^85\defstringchar^^86\defstringchar^^87% - \defstringchar^^88\defstringchar^^89\defstringchar^^8a\defstringchar^^8b% - \defstringchar^^8c\defstringchar^^8d\defstringchar^^8e\defstringchar^^8f% - % - \defstringchar^^90\defstringchar^^91\defstringchar^^92\defstringchar^^93% - \defstringchar^^94\defstringchar^^95\defstringchar^^96\defstringchar^^97% - \defstringchar^^98\defstringchar^^99\defstringchar^^9a\defstringchar^^9b% - \defstringchar^^9c\defstringchar^^9d\defstringchar^^9e\defstringchar^^9f% - % - \defstringchar^^a0\defstringchar^^a1\defstringchar^^a2\defstringchar^^a3% - \defstringchar^^a4\defstringchar^^a5\defstringchar^^a6\defstringchar^^a7% - \defstringchar^^a8\defstringchar^^a9\defstringchar^^aa\defstringchar^^ab% - \defstringchar^^ac\defstringchar^^ad\defstringchar^^ae\defstringchar^^af% - % - \defstringchar^^b0\defstringchar^^b1\defstringchar^^b2\defstringchar^^b3% - \defstringchar^^b4\defstringchar^^b5\defstringchar^^b6\defstringchar^^b7% - \defstringchar^^b8\defstringchar^^b9\defstringchar^^ba\defstringchar^^bb% - \defstringchar^^bc\defstringchar^^bd\defstringchar^^be\defstringchar^^bf% - % - \defstringchar^^c0\defstringchar^^c1\defstringchar^^c2\defstringchar^^c3% - \defstringchar^^c4\defstringchar^^c5\defstringchar^^c6\defstringchar^^c7% - \defstringchar^^c8\defstringchar^^c9\defstringchar^^ca\defstringchar^^cb% - \defstringchar^^cc\defstringchar^^cd\defstringchar^^ce\defstringchar^^cf% - % - \defstringchar^^d0\defstringchar^^d1\defstringchar^^d2\defstringchar^^d3% - \defstringchar^^d4\defstringchar^^d5\defstringchar^^d6\defstringchar^^d7% - \defstringchar^^d8\defstringchar^^d9\defstringchar^^da\defstringchar^^db% - \defstringchar^^dc\defstringchar^^dd\defstringchar^^de\defstringchar^^df% - % - \defstringchar^^e0\defstringchar^^e1\defstringchar^^e2\defstringchar^^e3% - \defstringchar^^e4\defstringchar^^e5\defstringchar^^e6\defstringchar^^e7% - \defstringchar^^e8\defstringchar^^e9\defstringchar^^ea\defstringchar^^eb% - \defstringchar^^ec\defstringchar^^ed\defstringchar^^ee\defstringchar^^ef% - % - \defstringchar^^f0\defstringchar^^f1\defstringchar^^f2\defstringchar^^f3% - \defstringchar^^f4\defstringchar^^f5\defstringchar^^f6\defstringchar^^f7% - \defstringchar^^f8\defstringchar^^f9\defstringchar^^fa\defstringchar^^fb% - \defstringchar^^fc\defstringchar^^fd\defstringchar^^fe\defstringchar^^ff% +% Native Unicode handling (XeTeX and LuaTeX) character replacing definition. +% It activates the setting that replaces Unicode characters. +\def\nativeunicodechardefs{% + \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative + \unicodechardefs } +% For native Unicode handling (XeTeX and LuaTeX), +% make the character token expand +% to the sequences given in \unicodechardefs for printing. +\def\DeclareUnicodeCharacterNativeAtU#1#2{% + \def\UTFAtUTmp{#2} + \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp +} + +% @U command definitions for native Unicode handling (XeTeX and LuaTeX). +\def\nativeunicodechardefsatu{% + \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU + \unicodechardefs +} + +% US-ASCII character definitions. +\def\asciichardefs{% nothing need be done + \relax +} -% define all the unicode characters we know about, for the sake of @U. -\utfeightchardefs +% define all Unicode characters we know about, for the sake of @U. +\iftxinativeunicodecapable + \nativeunicodechardefsatu +\else + \utfeightchardefs +\fi % Make non-ASCII characters printable again for compatibility with @@ -10801,12 +11319,12 @@ callback.register("process_output_buffer", convert_line_out) \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin - \pageheight = \vsize + \txipageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in - \pagewidth = \hsize + \txipagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax @@ -10818,6 +11336,14 @@ callback.register("process_output_buffer", convert_line_out) % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in + \else + \ifx\XeTeXrevision\thisisundefined + \special{papersize=#8,#7}% + \else + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + % XeTeX does not have \pdfhorigin and \pdfvorigin. + \fi \fi % \setleading{\textleading} @@ -10850,7 +11376,6 @@ callback.register("process_output_buffer", convert_line_out) % \lispnarrowing = 0.3in \tolerance = 700 - \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} @@ -10868,7 +11393,6 @@ callback.register("process_output_buffer", convert_line_out) % \lispnarrowing = 0.25in \tolerance = 700 - \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} @@ -10894,7 +11418,6 @@ callback.register("process_output_buffer", convert_line_out) {297mm}{210mm}% % \tolerance = 700 - \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} @@ -10913,7 +11436,6 @@ callback.register("process_output_buffer", convert_line_out) % \lispnarrowing = 0.2in \tolerance = 800 - \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm @@ -10974,9 +11496,11 @@ callback.register("process_output_buffer", convert_line_out) % \dimen0 = #1\relax \advance\dimen0 by \voffset + \advance\dimen0 by 1in % reference point for DVI is 1 inch from top of page % \dimen2 = \hsize \advance\dimen2 by \normaloffset + \advance\dimen2 by 1in % reference point is 1 inch from left edge of page % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% @@ -10988,6 +11512,9 @@ callback.register("process_output_buffer", convert_line_out) % \letterpaper +% Default value of \hfuzz, for suppressing warnings about overfull hboxes. +\hfuzz = 1pt + \message{and turning on texinfo input format.} @@ -11111,7 +11638,7 @@ callback.register("process_output_buffer", convert_line_out) % {@catcode`- = @active @gdef@normalturnoffactive{% - @nonasciistringdefs + @passthroughcharstrue @let-=@normaldash @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @@ -11149,9 +11676,13 @@ callback.register("process_output_buffer", convert_line_out) @global@let\ = @eatinput% @catcode`@^^M=13% @def@c{@fixbackslash@c}% + % Definition for the newline at the end of this file. @def ^^M{@let^^M@secondlinenl}% - @gdef @secondlinenl{@let^^M@thirdlinenl}% - @gdef @thirdlinenl{@fixbackslash}% + % Definition for a newline in the main Texinfo file. + @gdef @secondlinenl{@fixbackslash}% + % In case the first line has a whole-line command on it + @let@originalparsearg@parsearg + @def@parsearg{@fixbackslash@originalparsearg} }} {@catcode`@^=7 @catcode`@^^M=13% @@ -11172,6 +11703,7 @@ callback.register("process_output_buffer", convert_line_out) @catcode13=5 % regular end of line @enableemergencynewline @let@c=@texinfoc + @let@parsearg@originalparsearg % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. @catcode`+=@active @@ -11216,7 +11748,7 @@ callback.register("process_output_buffer", convert_line_out) @markupsetuprqdefault @c Local variables: -@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c eval: (add-hook 'before-save-hook 'time-stamp) @c page-delimiter: "^\\\\message\\|emacs-page" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @@ -11225,7 +11757,4 @@ callback.register("process_output_buffer", convert_line_out) @c vim:sw=2: -@ignore - arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 -@end ignore @enablebackslashhack diff --git a/doc/wordlist b/doc/wordlist index f3729905..d87a1b1b 100644 --- a/doc/wordlist +++ b/doc/wordlist @@ -38,6 +38,7 @@ Automake Autotools Avahi Awk +Awklib Awkstuff Ayalon BBBB @@ -65,6 +66,9 @@ Broderick Buening Burridge BusyBox +Bycount +Byname +Byuid CAKuGj CASEFOLD CC @@ -251,6 +255,8 @@ Igawk Illumos Incrementing Inf +Init +Inited Inplace InstallingGNVPackages Internetworking @@ -1091,6 +1097,7 @@ getgruser getline getlocaltime getopt +getpid getpwent getpwnam getpwuid @@ -1449,6 +1456,7 @@ nonwhitespace noone nr nroff +ns nul num numfields @@ -1794,6 +1802,7 @@ testbits testdir testext testff +testpasswd tew tex texi @@ -1973,6 +1982,7 @@ yearday ylwrap yourprog yxaay +yyy zA zbcom zerofile @@ -330,6 +330,7 @@ static struct optypetab { { "Op_K_getline_redir", "getline" }, { "Op_K_getline", "getline" }, { "Op_K_nextfile", "nextfile" }, + { "Op_K_namespace", "@namespace" }, { "Op_builtin", NULL }, { "Op_sub_builtin", NULL }, { "Op_ext_builtin", NULL }, @@ -400,7 +401,7 @@ nodetype2str(NODETYPE type) return buf; } -/* opcode2str --- convert a opcode type into a printable value */ +/* opcode2str --- convert an opcode type into a printable value */ const char * opcode2str(OPCODE op) @@ -411,6 +412,8 @@ opcode2str(OPCODE op) return NULL; } +/* op2str --- convert an opcode type to corresponding operator or keyword */ + const char * op2str(OPCODE op) { @@ -79,7 +79,7 @@ load_ext(const char *lib_name) /* is_valid_identifier --- return true if name is a valid simple identifier */ -static bool +bool is_valid_identifier(const char *name) { const char *sp = name; @@ -99,12 +99,13 @@ is_valid_identifier(const char *name) /* make_builtin --- register name to be called as func with a builtin body */ awk_bool_t -make_builtin(const awk_ext_func_t *funcinfo) +make_builtin(const char *name_space, const awk_ext_func_t *funcinfo) { NODE *symbol, *f; INSTRUCTION *b; const char *name = funcinfo->name; int count = funcinfo->max_expected_args; + const char *install_name; if (name == NULL || *name == '\0') fatal(_("make_builtin: missing function name")); @@ -112,9 +113,33 @@ make_builtin(const awk_ext_func_t *funcinfo) if (! is_valid_identifier(name)) return awk_false; - f = lookup(name); + assert(name_space != NULL); + if (name_space[0] == '\0' || strcmp(name_space, awk_namespace) == 0) { + if (check_special(name) >= 0) + fatal(_("make_builtin: can't use gawk built-in `%s' as function name"), name); + + f = lookup(name, false); + install_name = estrdup(name, strlen(name)); + } else { + if (! is_valid_identifier(name_space)) + return awk_false; + + if (check_special(name_space) >= 0) + fatal(_("make_builtin: can't use gawk built-in `%s' as namespace name"), name_space); + if (check_special(name) >= 0) + fatal(_("make_builtin: can't use gawk built-in `%s' as function name"), name); + + size_t len = strlen(name_space) + 2 + strlen(name) + 1; + char *buf; + emalloc(buf, char *, len, "make_builtin"); + sprintf(buf, "%s::%s", name_space, name); + install_name = buf; + + f = lookup(install_name, false); + } if (f != NULL) { + // found it, but it shouldn't be there if we want to install this function if (f->type == Node_func) { /* user-defined function */ fatal(_("make_builtin: can't redefine function `%s'"), name); @@ -126,8 +151,7 @@ make_builtin(const awk_ext_func_t *funcinfo) } else /* variable name etc. */ fatal(_("make_builtin: function name `%s' previously defined"), name); - } else if (check_special(name) >= 0) - fatal(_("make_builtin: can't use gawk built-in `%s' as function name"), name); + } if (count < 0) fatal(_("make_builtin: negative argument count for function `%s'"), @@ -139,7 +163,7 @@ make_builtin(const awk_ext_func_t *funcinfo) /* NB: extension sub must return something */ - symbol = install_symbol(estrdup(name, strlen(name)), Node_ext_func); + symbol = install_symbol(install_name, Node_ext_func); symbol->code_ptr = b; track_ext_func(name); return awk_true; diff --git a/extension/ChangeLog b/extension/ChangeLog index 69127623..35b82970 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -56,6 +56,10 @@ * intdiv.c (do_intdiv): Print a warning about loss of precision if MPFR arguments are received when not compiled with MPFR support. +2018-02-11 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.3am: Fix some typos. + 2018-02-08 Andrew J. Schorr <aschorr@telemetry-investments.com> * configure.ac (pkgextensiondir): This must be set to @@ -71,6 +75,13 @@ revtwoway.3am, rwarray.3am, time.3am: Add vim modeline at the bottom to set the file type for syntax coloring. +2018-02-02 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c (FTS_SKIP): New constant. + (process): Additional arg skipset. When true (based on if + FTS_SKIP was passed) and at level 0, use fts_set to set + FTS_SKIP on the directory. + 2018-01-11 Arnold D. Robbins <arnold@skeeve.com> * compile, config.guess, config.rpath, config.sub, @@ -192,6 +203,18 @@ * Makefile.am: Update copyright year. +2017-07-20 Arnold D. Robbins <arnold@skeeve.com> + + * inplace.c: Move functions into "inplace" namespace and simplify + the names. Update all error messages accordingly. + +2017-07-13 Arnold D. Robbins <arnold@skeeve.com> + + * testext.c (init_test_ext): Add installation of a variable and a + function in a namespace, and test using them. + (do_test_function): New function. + (ns_test_func): New function entry for it. + 2017-06-27 Arnold D. Robbins <arnold@skeeve.com> * Makfile.am (intdiv_la_LIBADD): Add LIBMPFR for Cygwin. diff --git a/extension/filefuncs.3am b/extension/filefuncs.3am index 36acf649..571fdea9 100644 --- a/extension/filefuncs.3am +++ b/extension/filefuncs.3am @@ -230,6 +230,9 @@ This option causes entries for ``..'' to also be included. .TP .B FTS_XDEV During a traversal, do not cross onto a different mounted filesystem. +.TP +.B FTS_SKIP +When set, causes top level directories to not be descended into. .RE .TP .B filedata @@ -321,6 +324,10 @@ the changed values are passed to .SH BUGS There are many more file-related functions for which AWK interfaces would be desirable. +.PP +It's not clear why I thought adding +.B FTS_SKIP +was a good idea. .SH EXAMPLE See .B test/fts.awk diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 1cf37453..1ea25dbc 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -575,6 +575,7 @@ init_filefuncs(void) ENTRY(FTS_PHYSICAL), ENTRY(FTS_SEEDOT), ENTRY(FTS_XDEV), + ENTRY(FTS_SKIP), { NULL, 0 } }; @@ -690,7 +691,7 @@ fill_default_elements(awk_array_t element_array, const FTSENT *const fentry, awk /* process --- process the hierarchy */ static void -process(FTS *hierarchy, awk_array_t destarray, int seedot) +process(FTS *hierarchy, awk_array_t destarray, int seedot, int skipset) { FTSENT *fentry; awk_value_t index, value; @@ -705,7 +706,12 @@ process(FTS *hierarchy, awk_array_t destarray, int seedot) switch (fentry->fts_info) { case FTS_D: /* directory */ + + if (skipset && fentry->fts_level == 0) + fts_set(hierarchy, fentry, FTS_SKIP); + /* create array to hold entries */ + /* this will be empty if doing FTS_SKIP */ newdir_array = create_array(); if (newdir_array == NULL) { warning(ext_id, _("fts-process: could not create array")); @@ -826,7 +832,7 @@ do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused) int ret = -1; static const int mask = ( FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_PHYSICAL - | FTS_SEEDOT | FTS_XDEV); + | FTS_SEEDOT | FTS_XDEV | FTS_SKIP); assert(result != NULL); fts_errors = 0; /* ensure a fresh start */ @@ -894,7 +900,7 @@ do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused) /* let's do it! */ if ((hierarchy = fts_open(pathvector, flags, NULL)) != NULL) { - process(hierarchy, dest.array_cookie, (flags & FTS_SEEDOT) != 0); + process(hierarchy, dest.array_cookie, (flags & FTS_SEEDOT) != 0, (flags & FTS_SKIP) != 0); fts_close(hierarchy); if (fts_errors == 0) diff --git a/extension/inplace.c b/extension/inplace.c index 516edc97..d2a04118 100644 --- a/extension/inplace.c +++ b/extension/inplace.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2013-2015, 2018, the Free Software Foundation, Inc. + * Copyright (C) 2013-2015, 2017, 2018, the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -128,13 +128,13 @@ do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused) fflush(stdout); if (state.tname) - fatal(ext_id, _("inplace_begin: in-place editing already active")); + fatal(ext_id, _("inplace::begin: in-place editing already active")); if (nargs != 2) - fatal(ext_id, _("inplace_begin: expects 2 arguments but called with %d"), nargs); + fatal(ext_id, _("inplace::begin: expects 2 arguments but called with %d"), nargs); if (! get_argument(0, AWK_STRING, &filename)) - fatal(ext_id, _("inplace_begin: cannot retrieve 1st argument as a string filename")); + fatal(ext_id, _("inplace::begin: cannot retrieve 1st argument as a string filename")); /* * N.B. In the current implementation, the 2nd suffix arg is not used @@ -142,21 +142,21 @@ do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused) */ if (invalid_filename(&filename.str_value)) { - warning(ext_id, _("inplace_begin: disabling in-place editing for invalid FILENAME `%s'"), + warning(ext_id, _("inplace::begin: disabling in-place editing for invalid FILENAME `%s'"), filename.str_value.str); unset_ERRNO(); return make_number(-1, result); } if (stat(filename.str_value.str, & sbuf) < 0) { - warning(ext_id, _("inplace_begin: Cannot stat `%s' (%s)"), + warning(ext_id, _("inplace::begin: Cannot stat `%s' (%s)"), filename.str_value.str, strerror(errno)); update_ERRNO_int(errno); return make_number(-1, result); } if (! S_ISREG(sbuf.st_mode)) { - warning(ext_id, _("inplace_begin: `%s' is not a regular file"), + warning(ext_id, _("inplace::begin: `%s' is not a regular file"), filename.str_value.str); unset_ERRNO(); return make_number(-1, result); @@ -167,7 +167,7 @@ do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused) sprintf(state.tname, "%s.gawk.XXXXXX", filename.str_value.str); if ((fd = mkstemp(state.tname)) < 0) - fatal(ext_id, _("inplace_begin: mkstemp(`%s') failed (%s)"), + fatal(ext_id, _("inplace::begin: mkstemp(`%s') failed (%s)"), state.tname, strerror(errno)); /* N.B. chown/chmod should be more portable than fchown/fchmod */ @@ -179,20 +179,20 @@ do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused) } if (chmod(state.tname, sbuf.st_mode) < 0) - fatal(ext_id, _("inplace_begin: chmod failed (%s)"), + fatal(ext_id, _("inplace::begin: chmod failed (%s)"), strerror(errno)); fflush(stdout); /* N.B. fgetpos fails when stdout is a tty */ state.posrc = fgetpos(stdout, &state.pos); if ((state.default_stdout = dup(STDOUT_FILENO)) < 0) - fatal(ext_id, _("inplace_begin: dup(stdout) failed (%s)"), + fatal(ext_id, _("inplace::begin: dup(stdout) failed (%s)"), strerror(errno)); if (dup2(fd, STDOUT_FILENO) < 0) - fatal(ext_id, _("inplace_begin: dup2(%d, stdout) failed (%s)"), + fatal(ext_id, _("inplace::begin: dup2(%d, stdout) failed (%s)"), fd, strerror(errno)); if (close(fd) < 0) - fatal(ext_id, _("inplace_begin: close(%d) failed (%s)"), + fatal(ext_id, _("inplace::begin: close(%d) failed (%s)"), fd, strerror(errno)); rewind(stdout); return make_number(0, result); @@ -208,30 +208,30 @@ do_inplace_end(int nargs, awk_value_t *result, struct awk_ext_func *unused) assert(result != NULL); if (nargs != 2) - fatal(ext_id, _("inplace_end: expects 2 arguments but called with %d"), nargs); + fatal(ext_id, _("inplace::end: expects 2 arguments but called with %d"), nargs); if (! get_argument(0, AWK_STRING, &filename)) - fatal(ext_id, _("inplace_end: cannot retrieve 1st argument as a string filename")); + fatal(ext_id, _("inplace::end: cannot retrieve 1st argument as a string filename")); if (! get_argument(1, AWK_STRING, &suffix)) suffix.str_value.str = NULL; if (! state.tname) { if (! invalid_filename(&filename.str_value)) - warning(ext_id, _("inplace_end: in-place editing not active")); + warning(ext_id, _("inplace::end: in-place editing not active")); return make_number(0, result); } fflush(stdout); if (dup2(state.default_stdout, STDOUT_FILENO) < 0) - fatal(ext_id, _("inplace_end: dup2(%d, stdout) failed (%s)"), + fatal(ext_id, _("inplace::end: dup2(%d, stdout) failed (%s)"), state.default_stdout, strerror(errno)); if (close(state.default_stdout) < 0) - fatal(ext_id, _("inplace_end: close(%d) failed (%s)"), + fatal(ext_id, _("inplace::end: close(%d) failed (%s)"), state.default_stdout, strerror(errno)); state.default_stdout = -1; if (state.posrc == 0 && fsetpos(stdout, &state.pos) < 0) - fatal(ext_id, _("inplace_end: fsetpos(stdout) failed (%s)"), + fatal(ext_id, _("inplace::end: fsetpos(stdout) failed (%s)"), strerror(errno)); if (suffix.str_value.str && suffix.str_value.str[0]) { @@ -254,7 +254,7 @@ do_inplace_end(int nargs, awk_value_t *result, struct awk_ext_func *unused) #endif if (rename(state.tname, filename.str_value.str) < 0) - fatal(ext_id, _("inplace_end: rename(`%s', `%s') failed (%s)"), + fatal(ext_id, _("inplace::end: rename(`%s', `%s') failed (%s)"), state.tname, filename.str_value.str, strerror(errno)); gawk_free(state.tname); state.tname = NULL; @@ -262,8 +262,8 @@ do_inplace_end(int nargs, awk_value_t *result, struct awk_ext_func *unused) } static awk_ext_func_t func_table[] = { - { "inplace_begin", do_inplace_begin, 2, 2, awk_false, NULL }, - { "inplace_end", do_inplace_end, 2, 2, awk_false, NULL }, + { "begin", do_inplace_begin, 2, 2, awk_false, NULL }, + { "end", do_inplace_end, 2, 2, awk_false, NULL }, }; static awk_bool_t init_inplace(void) @@ -276,4 +276,4 @@ static awk_bool_t (*init_func)(void) = init_inplace; /* define the dl_load function using the boilerplate macro */ -dl_load_func(func_table, inplace, "") +dl_load_func(func_table, inplace, "inplace") diff --git a/extension/testext.c b/extension/testext.c index 6629296a..b911ec93 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2012, 2013, 2014, 2015, 2018 + * Copyright (C) 2012, 2013, 2014, 2015, 2017, 2018 * the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the @@ -1034,6 +1034,17 @@ static void at_exit2(void *data, int exit_status) printf(" exit_status = %d\n", exit_status); } +/* do_test_function --- test function for test namespace */ + +static awk_value_t * +do_test_function(int nargs, awk_value_t *result, struct awk_ext_func *unused) +{ + printf("test::test_function() called.\n"); + fflush(stdout); + + return make_number(0.0, result); +} + static awk_ext_func_t func_table[] = { { "dump_array_and_delete", dump_array_and_delete, 2, 2, awk_false, NULL }, { "try_modify_environ", try_modify_environ, 0, 0, awk_false, NULL }, @@ -1051,6 +1062,10 @@ static awk_ext_func_t func_table[] = { { "get_file", do_get_file, 4, 4, awk_false, NULL }, }; +static awk_ext_func_t ns_test_func = { + "test_function", do_test_function, 0, 0, awk_false, NULL +}; + /* init_testext --- additional initialization function */ static awk_bool_t init_testext(void) @@ -1058,6 +1073,7 @@ static awk_bool_t init_testext(void) awk_value_t value; static const char message[] = "hello, world"; /* of course */ static const char message2[] = "i am a scalar"; + static const char message3[] = "in namespace test"; /* This is used by the getfile test */ if (sym_lookup("TESTEXT_QUIET", AWK_NUMBER, & value)) @@ -1075,6 +1091,9 @@ BEGIN { for (i in new_array) printf("new_array[\"%s\"] = \"%s\"\n", i, new_array[i]) print "" + printf("test::testval = %s\n", test::testval) + test::test_function() + print "" } */ @@ -1092,6 +1111,13 @@ BEGIN { create_new_array(); + if (! sym_update_ns("test", "testval", + make_const_string(message3, strlen(message3), & value))) + printf("testext: sym_update_ns(\"test\", \"testval\") failed!\n"); + + if (! add_ext_func("test", & ns_test_func)) + printf("testext: add_ext_func(\"test\", ns_test_func) failed!\n"); + return awk_true; } @@ -40,6 +40,7 @@ extern int currule; static awk_bool_t node_to_awk_value(NODE *node, awk_value_t *result, awk_valtype_t wanted); static char *valtype2str(awk_valtype_t type); +static NODE *ns_lookup(const char *name_space, const char *name, char **full_name); /* * api_get_argument --- get the count'th paramater, zero-based. @@ -372,17 +373,19 @@ api_unset_ERRNO(awk_ext_id_t id) static awk_bool_t api_add_ext_func(awk_ext_id_t id, - const char *namespace, + const char *name_space, awk_ext_func_t *func) { (void) id; - (void) namespace; if (func == NULL) return awk_false; + if (name_space == NULL) + fatal(_("add_ext_func: received NULL name_space parameter")); + #ifdef DYNAMIC - return make_builtin(func); + return make_builtin(name_space, func); #else return awk_false; #endif @@ -747,6 +750,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted) static awk_bool_t api_sym_lookup(awk_ext_id_t id, + const char *name_space, const char *name, awk_valtype_t wanted, awk_value_t *result) @@ -758,7 +762,12 @@ api_sym_lookup(awk_ext_id_t id, if ( name == NULL || *name == '\0' || result == NULL - || (node = lookup(name)) == NULL) + || ! is_valid_identifier(name) + || name_space == NULL + || (name_space[0] != '\0' && ! is_valid_identifier(name_space))) + return awk_false; + + if ((node = ns_lookup(name_space, name, NULL)) == NULL) return awk_false; if (is_off_limits_var(name)) /* a built-in variable */ @@ -791,6 +800,7 @@ api_sym_lookup_scalar(awk_ext_id_t id, static awk_bool_t api_sym_update(awk_ext_id_t id, + const char *name_space, const char *name, awk_value_t *value) { @@ -799,7 +809,10 @@ api_sym_update(awk_ext_id_t id, if ( name == NULL || *name == '\0' - || value == NULL) + || value == NULL + || ! is_valid_identifier(name) + || name_space == NULL + || (name_space[0] != '\0' && ! is_valid_identifier(name_space))) return awk_false; switch (value->val_type) { @@ -818,22 +831,21 @@ api_sym_update(awk_ext_id_t id, return awk_false; } - node = lookup(name); + char *full_name = NULL; + node = ns_lookup(name_space, name, & full_name); if (node == NULL) { /* new value to be installed */ if (value->val_type == AWK_ARRAY) { array_node = awk_value_to_node(value); - node = install_symbol(estrdup((char *) name, strlen(name)), - Node_var_array); + node = install_symbol(full_name, Node_var_array); array_node->vname = node->vname; *node = *array_node; freenode(array_node); value->array_cookie = node; /* pass new cookie back to extension */ } else { /* regular variable */ - node = install_symbol(estrdup((char *) name, strlen(name)), - Node_var); + node = install_symbol(full_name, Node_var); node->var_value = awk_value_to_node(value); } @@ -845,11 +857,14 @@ api_sym_update(awk_ext_id_t id, * OK except for AWK_ARRAY. */ if ( (node->flags & NO_EXT_SET) != 0 - || is_off_limits_var(name)) { /* most built-in vars not allowed */ + || is_off_limits_var(full_name)) { /* most built-in vars not allowed */ node->flags |= NO_EXT_SET; + efree((void *) full_name); return awk_false; } + efree((void *) full_name); + if ( value->val_type != AWK_ARRAY && (node->type == Node_var || node->type == Node_var_new)) { unref(node->var_value); @@ -1179,7 +1194,7 @@ api_flatten_array_typed(awk_ext_id_t id, if ( array == NULL || array->type != Node_var_array - || array->table_size == 0 + || assoc_empty(array) || data == NULL) return awk_false; @@ -1581,3 +1596,31 @@ valtype2str(awk_valtype_t type) return buf; } + +/* ns_lookup --- correctly build name before looking it up */ + +static NODE * +ns_lookup(const char *name_space, const char *name, char **fullname) +{ + assert(name_space != NULL); + assert(name != NULL); + + if (name_space[0] == '\0' || strcmp(name_space, awk_namespace) == 0) { + if (fullname != NULL) + *fullname = estrdup(name, strlen(name)); + return lookup(name, false); + } + + size_t len = strlen(name_space) + 2 + strlen(name) + 1; + char *buf; + emalloc(buf, char *, len, "ns_lookup"); + sprintf(buf, "%s::%s", name_space, name); + + NODE *f = lookup(buf, false); + if (fullname != NULL) + *fullname = buf; + else + efree((void *) buf); + + return f; +} @@ -623,6 +623,7 @@ typedef struct gawk_api { * } */ awk_bool_t (*api_sym_lookup)(awk_ext_id_t id, + const char *name_space, const char *name, awk_valtype_t wanted, awk_value_t *result); @@ -634,6 +635,7 @@ typedef struct gawk_api { * Such an attempt returns false. */ awk_bool_t (*api_sym_update)(awk_ext_id_t id, + const char *name_space, const char *name, awk_value_t *value); @@ -867,11 +869,17 @@ typedef struct gawk_api { #define awk_atexit(funcp, arg0) (api->api_awk_atexit(ext_id, funcp, arg0)) #define sym_lookup(name, wanted, result) \ - (api->api_sym_lookup(ext_id, name, wanted, result)) + sym_lookup_ns("", name, wanted, result) +#define sym_update(name, value) \ + sym_update_ns("", name, value) + +#define sym_lookup_ns(name_space, name, wanted, result) \ + (api->api_sym_lookup(ext_id, name_space, name, wanted, result)) +#define sym_update_ns(name_space, name, value) \ + (api->api_sym_update(ext_id, name_space, name, value)) + #define sym_lookup_scalar(scalar_cookie, wanted, result) \ (api->api_sym_lookup_scalar(ext_id, scalar_cookie, wanted, result)) -#define sym_update(name, value) \ - (api->api_sym_update(ext_id, name, value)) #define sym_update_scalar(scalar_cookie, value) \ (api->api_sym_update_scalar)(ext_id, scalar_cookie, value) diff --git a/int_array.c b/int_array.c index 069e027d..475f16fe 100644 --- a/int_array.c +++ b/int_array.c @@ -46,10 +46,10 @@ static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1); static NODE **int_insert(NODE *symbol, long k, uint32_t hash1); static void grow_int_table(NODE *symbol); -afunc_t int_array_func[] = { +const array_funcs_t int_array_func = { + "int", int_array_init, is_integer, - null_length, int_lookup, int_exists, int_clear, diff --git a/interpret.h b/interpret.h index 2934c5c0..82329e85 100644 --- a/interpret.h +++ b/interpret.h @@ -351,16 +351,19 @@ uninitialized_scalar: * 3. Values that awk code stuck into SYMTAB not related to variables (Node_value) * For 1, since we are giving it a value, we have to change the type to Node_var. * For 1 and 2, we have to step through the Node_var to get to the value. - * For 3, we just us the value we got from assoc_lookup(), above. + * For 3, we fatal out. This avoids confusion on things like + * SYMTAB["a foo"] = 42 # variable with a space in its name? */ if (t1 == func_table) fatal(_("cannot assign to elements of FUNCTAB")); - else if ( t1 == symbol_table - && ( (*lhs)->type == Node_var + else if (t1 == symbol_table) { + if (( (*lhs)->type == Node_var || (*lhs)->type == Node_var_new)) { - update_global_values(); /* make sure stuff like NF, NR, are up to date */ - (*lhs)->type = Node_var; /* in case was Node_var_new */ - lhs = & ((*lhs)->var_value); /* extra level of indirection */ + update_global_values(); /* make sure stuff like NF, NR, are up to date */ + (*lhs)->type = Node_var; /* in case was Node_var_new */ + lhs = & ((*lhs)->var_value); /* extra level of indirection */ + } else + fatal(_("cannot assign to arbitrary elements of SYMTAB")); } assert(set_idx == NULL); @@ -661,22 +664,25 @@ mod: /* * Changing something in FUNCTAB is not allowed. * - * SYMTAB is a little more messy. Three kinds of values may - * be stored in SYMTAB: + * SYMTAB is a little more messy. Three possibilities for SYMTAB: * 1. Variables that don"t yet have a value (Node_var_new) * 2. Variables that have a value (Node_var) * 3. Values that awk code stuck into SYMTAB not related to variables (Node_value) * For 1, since we are giving it a value, we have to change the type to Node_var. * For 1 and 2, we have to step through the Node_var to get to the value. - * For 3, we just us the value we got from assoc_lookup(), above. + * For 3, we fatal out. This avoids confusion on things like + * SYMTAB["a foo"] = 42 # variable with a space in its name? */ if (t1 == func_table) fatal(_("cannot assign to elements of FUNCTAB")); - else if ( t1 == symbol_table - && ( (*lhs)->type == Node_var + else if (t1 == symbol_table) { + if (( (*lhs)->type == Node_var || (*lhs)->type == Node_var_new)) { - (*lhs)->type = Node_var; /* in case was Node_var_new */ - lhs = & ((*lhs)->var_value); /* extra level of indirection */ + update_global_values(); /* make sure stuff like NF, NR, are up to date */ + (*lhs)->type = Node_var; /* in case was Node_var_new */ + lhs = & ((*lhs)->var_value); /* extra level of indirection */ + } else + fatal(_("cannot assign to arbitrary elements of SYMTAB")); } unref(*lhs); @@ -1108,7 +1114,7 @@ match_re: ni = setup_frame(pc); JUMPTO(ni); /* Op_func */ } - f = lookup(t1->stptr); + f = lookup(t1->stptr, true); } if (f == NULL) { @@ -1172,7 +1178,7 @@ match_re: /* retrieve function definition node */ f = pc->func_body; if (f == NULL) { - f = lookup(pc->func_name); + f = lookup(pc->func_name, true); if (f == NULL || (f->type != Node_func && f->type != Node_ext_func)) fatal(_("function `%s' not defined"), pc->func_name); pc->func_body = f; /* save for next call */ @@ -68,6 +68,7 @@ static void version(void) ATTRIBUTE_NORETURN; static void init_fds(void); static void init_groupset(void); static void save_argv(int, char **); +static const char *platform_name(); /* These nodes store all the special variables AWK uses */ NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node; @@ -397,9 +398,10 @@ main(int argc, char **argv) init_fields(); /* Now process the pre-assignments */ + int dash_v_errs = 0; // bad stuff for -v for (i = 0; i <= numassigns; i++) { if (preassigns[i].type == PRE_ASSIGN) - (void) arg_assign(preassigns[i].val, true); + dash_v_errs += (arg_assign(preassigns[i].val, true) == false); else /* PRE_ASSIGN_FS */ cmdline_fs(preassigns[i].val); efree(preassigns[i].val); @@ -463,12 +465,17 @@ main(int argc, char **argv) setlocale(LC_NUMERIC, "C"); #endif /* Read in the program */ - if (parse_program(& code_block) != 0) + if (parse_program(& code_block) != 0 || dash_v_errs > 0) exit(EXIT_FAILURE); if (do_intl) exit(EXIT_SUCCESS); + if (current_namespace != awk_namespace) { + efree((char *) current_namespace); + current_namespace = awk_namespace; + } + install_builtins(); if (do_lint) @@ -513,6 +520,7 @@ main(int argc, char **argv) interpret(code_block); if (do_pretty_print) { + current_namespace = awk_namespace; dump_prog(code_block); dump_funcs(); } @@ -981,6 +989,7 @@ load_procinfo() update_PROCINFO_str("version", VERSION); update_PROCINFO_str("strftime", def_strftime_format); + update_PROCINFO_str("platform", platform_name()); #ifdef HAVE_MPFR sprintf(name, "GNU MPFR %s", mpfr_get_version()); @@ -1143,7 +1152,7 @@ arg_assign(char *arg, bool initing) badvar = true; else for (cp2 = arg+1; *cp2; cp2++) - if (! is_identchar((unsigned char) *cp2)) { + if (! is_identchar((unsigned char) *cp2) && *cp2 != ':') { badvar = true; break; } @@ -1161,11 +1170,16 @@ arg_assign(char *arg, bool initing) // Assigning a string or typed regex + if (! validate_qualified_name(arg)) { + badvar = true; + goto done; + } + if (check_special(arg) >= 0) fatal(_("cannot use gawk builtin `%s' as variable name"), arg); if (! initing) { - var = lookup(arg); + var = lookup(arg, false); if (var != NULL && var->type == Node_func) fatal(_("cannot use function `%s' as variable name"), arg); } @@ -1769,3 +1783,24 @@ set_locale_stuff(void) (void) bindtextdomain(PACKAGE, locale_dir); (void) textdomain(PACKAGE); } + +/* platform_name --- return the platform name */ + +static const char * +platform_name() +{ + // Cygwin and Mac OS X count as POSIX +#if defined(__VMS) + return "vms"; +#elif defined(__MINGW32__) + return "mingw"; +#elif defined(__DJGPP__) + return "djgpp"; +#elif defined(__EMX__) + return "os2"; +#elif defined(USE_EBCDIC) + return "os390"; +#else + return "posix"; +#endif +} diff --git a/missing_d/ChangeLog b/missing_d/ChangeLog index 8d62768c..83cae855 100644 --- a/missing_d/ChangeLog +++ b/missing_d/ChangeLog @@ -51,6 +51,10 @@ * 4.2.0: Release tar ball made. +2017-10-13 Arnold D. Robbins <arnold@skeeve.com> + + * gawkbool.h: Removed. + 2017-10-08 Arnold D. Robbins <arnold@skeeve.com> * strncasecmp.c: Fix FSF's address. diff --git a/missing_d/gawkbool.h b/missing_d/gawkbool.h deleted file mode 100644 index c75a5a10..00000000 --- a/missing_d/gawkbool.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * gawkbool.h -- replacement definitions for bool. - */ - -/* - * Copyright (C) 2012 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 - */ - -/* This stuff largely taken from the Autoconf doc. */ - -#ifndef __bool_true_false_are_defined -# ifndef HAVE__BOOL -# ifdef __cplusplus -typedef bool _Bool; -# else -# define _Bool signed char -# endif -# endif -# define bool _Bool -# define false 0 -# define true 1 -# define __bool_true_false_are_defined 1 -#endif diff --git a/pc/Makefile.tst b/pc/Makefile.tst index 8611bce8..de66b877 100644 --- a/pc/Makefile.tst +++ b/pc/Makefile.tst @@ -149,10 +149,10 @@ BASIC_TESTS = \ callparam childin clobber closebad clsflnam compare compare2 \ concat1 concat2 concat3 concat4 concat5 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ - eofsplit exit2 exitval1 exitval2 exitval3 fcall_exit fcall_exit2 \ - fldchg fldchgnf fldterm fnamedat fnarray fnarray2 fnaryscl fnasgnm fnmisc \ - fordel forref forsimp fsbs fsnul1 fsrs fsspcoln fstabplus funsemnl \ - funsmnam funstack \ + eofsplit eofsrc1 exit2 exitval1 exitval2 exitval3 \ + fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \ + fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \ + fstabplus funsemnl funsmnam funstack \ getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \ gsubasgn gsubtest gsubtst2 gsubtst3 gsubtst4 gsubtst5 gsubtst6 gsubtst7 \ gsubtst8 \ @@ -201,18 +201,19 @@ GAWK_EXT_TESTS = \ incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \ indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \ - mixed1 mktime manyfiles match1 match2 match3 mbstr1 mbstr2 muldimposix \ + manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \ nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \ + nsbad nsbad_cmd nsindirect1 nsindirect2 nsprof1 nsprof2 \ patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge \ procinfs profile0 profile1 profile2 profile3 profile4 profile5 profile6 \ profile7 profile8 profile9 profile10 pty1 pty2 \ rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin \ rsstart1 rsstart2 rsstart3 rstest6 \ shadow shadowbuiltin sortfor sortfor2 sortu sourcesplit split_after_fpat \ - splitarg4 strftime strftfld strtonum strtonum1 switch2 symtab1 symtab2 \ + splitarg4 strftfld strftime strtonum strtonum1 switch2 symtab1 symtab2 \ symtab3 symtab4 symtab5 symtab6 symtab7 symtab8 symtab9 symtab10 \ - typedregex1 typedregex2 typedregex3 typeof1 typeof2 typeof3 typeof4 \ - typeof5 timeout \ + timeout typedregex1 typedregex2 typedregex3 typeof1 typeof2 typeof3 \ + typeof4 typeof5 \ watchpoint1 ARRAYDEBUG_TESTS = arrdbg @@ -261,7 +262,9 @@ NEED_NONDEC = mpfrbigint2 nondec2 intarray forcenum NEED_POSIX = printf0 posix2008sub paramasfunc1 paramasfunc2 muldimposix # List of tests that need --pretty-print -NEED_PRETTY = profile4 profile5 profile8 profile9 profile10 +NEED_PRETTY = nsprof1 nsprof2 \ + profile4 profile5 profile8 profile9 profile10 + # List of tests that need --re-interval NEED_RE_INTERVAL = gsubtst3 reint reint2 @@ -919,7 +922,7 @@ inplace2:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -930,8 +933,8 @@ inplace3:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -1094,6 +1097,16 @@ sourcesplit: @AWKPATH="$(srcdir)" $(AWK) --source='BEGIN { a = 5;' --source='print a }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +eofsrc1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f "$(srcdir)"/$@a.awk -f "$(srcdir)"/$@b.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsbad_cmd: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -v foo:bar=3 -v foo:::blat=4 1 /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + # Use [:] in the regexp to keep MSYS from converting the /'s to \'s. nonfatal1: @echo $@ @@ -2738,11 +2751,6 @@ lintwarn: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -mktime: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - match1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2772,6 +2780,11 @@ mbstr2: AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mktime: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + muldimposix: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2809,6 +2822,31 @@ nonfatal3: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +nsbad: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + patsplit: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3007,6 +3045,12 @@ symtab10: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +timeout: + @echo $@ + @echo Expect $@ to fail with DJGPP and MinGW. + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + typedregex1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3047,12 +3091,6 @@ typeof5: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -timeout: - @echo $@ - @echo Expect $@ to fail with DJGPP and MinGW. - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - double1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/pc/config.h b/pc/config.h index 77972517..6ebf5975 100644 --- a/pc/config.h +++ b/pc/config.h @@ -464,7 +464,7 @@ #define PACKAGE_NAME "GNU Awk" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "GNU Awk 4.2.1a" +#define PACKAGE_STRING "GNU Awk 4.2.60" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gawk" @@ -473,7 +473,7 @@ #define PACKAGE_URL "http://www.gnu.org/software/gawk/" /* Define to the version of this package. */ -#define PACKAGE_VERSION "4.2.1a" +#define PACKAGE_VERSION "4.2.60" /* Define to 1 if *printf supports %a format */ #define PRINTF_HAS_A_FORMAT 1 @@ -537,7 +537,7 @@ /* Version number of package */ -#define VERSION "4.2.1a" +#define VERSION "4.2.60" /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1999-2017 the Free Software Foundation, Inc. + * Copyright (C) 1999-2018 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -37,14 +37,18 @@ static char *pp_typed_regex(const char *in_str, size_t len, int delim); static bool is_binary(int type); static bool is_scalar(int type); static int prec_level(int type); -static void pp_push(int type, char *s, int flag); +static void pp_push(int type, char *s, int flag, INSTRUCTION *comment); static NODE *pp_pop(void); static void print_comment(INSTRUCTION *pc, long in); const char *redir2str(int redirtype); +static void pp_namespace(const char *name, INSTRUCTION *comment); +static void pp_namespace_list(INSTRUCTION *list); +static char *adjust_namespace(char *name, bool *malloced); #define pp_str vname #define pp_len sub.nodep.reserved #define pp_next rnode +#define pp_comment sub.nodep.x.cmnt #define DONT_FREE 1 #define CAN_FREE 2 @@ -60,6 +64,15 @@ static FILE *prof_fp; /* where to send the profile */ static long indent_level = 0; +static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; +static const size_t tabs_len = sizeof(tabs) - 1; + +#define check_indent_level() \ + if (indent_level + 1 > tabs_len) \ + /* We're allowed to be snarky, occasionally. */ \ + fatal(_("Program indentation level too deep. Consider refactoring your code")); + + #define SPACEOVER 0 #define NO_PPRINT_FLAGS 0 @@ -159,7 +172,7 @@ indent_out(void) /* pp_push --- push a pretty printed string onto the stack */ static void -pp_push(int type, char *s, int flag) +pp_push(int type, char *s, int flag, INSTRUCTION *comment) { NODE *n; getnode(n); @@ -168,6 +181,7 @@ pp_push(int type, char *s, int flag) n->flags = flag; n->type = type; n->pp_next = pp_stack; + n->pp_comment = comment; pp_stack = n; } @@ -225,22 +239,29 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) switch (pc->opcode) { case Op_rule: /* - * Rules are three instructions long. + * Rules are four instructions long. * See append_rule in awkgram.y. * The first has the Rule Op Code, nexti etc. * The second, (pc + 1) has firsti and lasti: * the first/last ACTION instructions for this rule. * The third has first_line and last_line: * the first and last source line numbers. + * The fourth holds the namespace name if there is one. + * (there should be one if we're in this file) + * This can actually be a list in reverse order if + * there were several @namespace directives one + * after the other. */ source = pc->source_file; rule = pc->in_rule; + pp_namespace_list(pc[3].nexti); + if (rule != Rule) { /* Allow for pre-non-rule-block comment */ - if (pc->nexti != (pc +1)->firsti + if (pc->nexti != (pc+1)->firsti && pc->nexti->opcode == Op_comment - && pc->nexti->memory->comment_type == FULL_COMMENT) + && pc->nexti->memory->comment_type == BLOCK_COMMENT) print_comment(pc->nexti, -1); ip1 = (pc + 1)->firsti; ip2 = (pc + 1)->lasti; @@ -302,9 +323,9 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) case Op_push_i: m = pc->memory; if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */ - pp_push(pc->opcode, m->stptr, DONT_FREE); + pp_push(pc->opcode, m->stptr, DONT_FREE, pc->comment); else if ((m->flags & NUMBER) != 0) - pp_push(pc->opcode, pp_number(m), CAN_FREE); + pp_push(pc->opcode, pp_number(m), CAN_FREE, pc->comment); else { str = pp_string(m->stptr, m->stlen, '"'); if ((m->flags & INTLSTR) != 0) { @@ -312,13 +333,13 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) str = pp_group3("_", tmp, ""); efree(tmp); } - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; case Op_store_var: if (pc->initval != NULL) - pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE); + pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE, pc->comment); /* fall through */ case Op_store_sub: case Op_assign_concat: @@ -331,15 +352,18 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) m = pc->memory; switch (m->type) { case Node_param_list: - pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE); + pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE, pc->comment); break; case Node_var: case Node_var_new: case Node_var_array: - if (m->vname != NULL) - pp_push(pc->opcode, m->vname, DONT_FREE); - else + if (m->vname != NULL) { + bool malloced = false; + char *name = adjust_namespace(m->vname, & malloced); + + pp_push(pc->opcode, name, malloced ? CAN_FREE : DONT_FREE, pc->comment); + } else fatal(_("internal error: %s with null vname"), nodetype2str(m->type)); break; @@ -390,7 +414,7 @@ cleanup: str = pp_group3(t1->pp_str, tmp, ""); efree(tmp); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_and: @@ -399,10 +423,24 @@ cleanup: t2 = pp_pop(); t1 = pp_pop(); parenthesize(pc->opcode, t1, t2); - str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); + if (pc->comment == NULL) + str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); + else { + check_indent_level(); + + size_t len = strlen(t1->pp_str) + + strlen(op2str(pc->opcode)) + strlen(t2->pp_str) // foo && bar + + indent_level + 1 // indent + + pc->comment->memory->stlen + 3; // tab comment + + emalloc(str, char *, len, "pprint"); + sprintf(str, "%s%s%s%.*s %s", t1->pp_str, op2str(pc->opcode), + pc->comment->memory->stptr, + (int) (indent_level + 1), tabs, t2->pp_str); + } pp_free(t1); pp_free(t2); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); pc = pc->target_jmp; break; @@ -424,14 +462,14 @@ cleanup: str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp); efree(tmp); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_parens: t1 = pp_pop(); str = pp_group3("(", t1->pp_str, ")"); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_plus: @@ -452,7 +490,7 @@ cleanup: str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); pp_free(t1); pp_free(t2); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_preincrement: @@ -465,7 +503,7 @@ cleanup: else str = pp_group3(t1->pp_str, op2str(pc->opcode), ""); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_field_spec: @@ -483,7 +521,7 @@ cleanup: /* optypes table (eval.c) includes space after ! */ str = pp_group3(op2str(pc->opcode), t1->pp_str, ""); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_assign: @@ -498,7 +536,7 @@ cleanup: str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str); pp_free(t2); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_store_field: @@ -515,7 +553,7 @@ cleanup: case Op_concat: str = pp_concat(pc->expr_count); - pp_push(Op_concat, str, CAN_FREE); + pp_push(Op_concat, str, CAN_FREE, pc->comment); break; case Op_K_delete: @@ -560,7 +598,7 @@ cleanup: pp_free(t2); } pp_free(t1); - pp_push(Op_in_array, str, CAN_FREE); + pp_push(Op_in_array, str, CAN_FREE, pc->comment); } break; @@ -595,7 +633,7 @@ cleanup: tmp = pp_list(pc->expr_count, "()", ", "); str = pp_group3(fname, tmp, ""); efree(tmp); - pp_push(Op_sub_builtin, str, CAN_FREE); + pp_push(Op_sub_builtin, str, CAN_FREE, pc->comment); } break; @@ -603,9 +641,10 @@ cleanup: case Op_ext_builtin: { const char *fname; - if (pc->opcode == Op_builtin) - fname = getfname(pc->builtin); - else + if (pc->opcode == Op_builtin) { + bool prepend_awk = (current_namespace != awk_namespace && strcmp(current_namespace, "awk") != 0); + fname = getfname(pc->builtin, prepend_awk); + } else fname = (pc + 1)->func_name; if (fname != NULL) { if (pc->expr_count > 0) { @@ -614,7 +653,7 @@ cleanup: efree(tmp); } else str = pp_group3(fname, "()", ""); - pp_push(Op_builtin, str, CAN_FREE); + pp_push(Op_builtin, str, CAN_FREE, pc->comment); } else fatal(_("internal error: builtin with null fname")); } @@ -624,7 +663,8 @@ cleanup: case Op_K_printf: case Op_K_print_rec: if (pc->opcode == Op_K_print_rec) - tmp = pp_group3(" ", op2str(Op_field_spec), "0"); + // instead of `print $0', just `print' + tmp = strdup(""); else if (pc->redir_type != 0) tmp = pp_list(pc->expr_count, "()", ", "); else { @@ -660,7 +700,7 @@ cleanup: assert((pc->memory->flags & REGEX) != 0); str = pp_typed_regex(pc->memory->stptr, pc->memory->stlen, '/'); } - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; @@ -692,7 +732,7 @@ cleanup: efree(restr); } pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; @@ -720,15 +760,16 @@ cleanup: pp_free(t2); } else str = tmp; - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_indirect_func_call: case Op_func_call: { - char *fname = pc->func_name; char *pre; int pcount; + bool malloced = false; + char *fname = adjust_namespace(pc->func_name, & malloced); if (pc->opcode == Op_indirect_func_call) pre = "@"; @@ -745,7 +786,10 @@ cleanup: t1 = pp_pop(); /* indirect var */ pp_free(t1); } - pp_push(pc->opcode, str, CAN_FREE); + + pp_push(pc->opcode, str, CAN_FREE, pc->comment); + if (malloced) + efree((void *) fname); } break; @@ -786,7 +830,7 @@ cleanup: str = pp_group3(t1->pp_str, ", ", t2->pp_str); pp_free(t1); pp_free(t2); - pp_push(Op_line_range, str, CAN_FREE); + pp_push(Op_line_range, str, CAN_FREE, pc->comment); pc = ip1->condpair_right; break; @@ -820,13 +864,34 @@ cleanup: indent(SPACEOVER); t1 = pp_pop(); fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str); + if (pc->comment) + fprintf(prof_fp, "\t%s", pc->comment->memory->stptr); + else { + end_line(pc->target_break); + skip_comment = true; + } pp_free(t1); - end_line(pc->target_break); - skip_comment = true; pc = pc->target_break; break; case Op_K_for: + { + INSTRUCTION *comment1 = NULL, *comment2 = NULL; + + if (pc->comment != NULL) { + comment1 = pc->comment; + pc->comment = NULL; + if (comment1 != NULL && comment1->comment != NULL) { + comment2 = comment1->comment; + comment1->comment = NULL; + } + if (comment2 == NULL && comment1->memory->comment_type == FOR_COMMENT) { + comment2 = comment1; + comment2->memory->comment_type = EOL_COMMENT; + comment1 = NULL; + } + } + ip1 = pc + 1; indent(ip1->forloop_body->exec_count); fprintf(prof_fp, "%s (", op2str(pc->opcode)); @@ -834,12 +899,19 @@ cleanup: /* If empty for looop header, print it a little more nicely. */ if ( pc->nexti->opcode == Op_no_op && ip1->forloop_cond == pc->nexti - && pc->target_continue->opcode == Op_jmp) { + && pc->target_continue->opcode == Op_jmp + && comment1 == NULL && comment2 == NULL) { fprintf(prof_fp, ";;"); } else { pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER); fprintf(prof_fp, "; "); + if (comment1 != NULL) { + print_comment(comment1, 0); + indent(ip1->forloop_body->exec_count); + indent(1); + } + if (ip1->forloop_cond->opcode == Op_no_op && ip1->forloop_cond->nexti == ip1->forloop_body) fprintf(prof_fp, "; "); @@ -850,6 +922,12 @@ cleanup: pp_free(t1); } + if (comment2 != NULL) { + print_comment(comment2, 0); + indent(ip1->forloop_body->exec_count); + indent(1); + } + pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER); } fprintf(prof_fp, ") {"); @@ -863,6 +941,7 @@ cleanup: end_line(pc->target_break); skip_comment = true; pc = pc->target_break; + } break; case Op_K_arrayfor: @@ -901,10 +980,14 @@ cleanup: pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS); t1 = pp_pop(); fprintf(prof_fp, "%s) {\n", t1->pp_str); + if (pc->comment) + print_comment(pc->comment, 0); pp_free(t1); pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS); indent(SPACEOVER); fprintf(prof_fp, "}\n"); + if (ip1->switch_end->comment) + print_comment(ip1->switch_end->comment, 0); pc = pc->target_break; break; @@ -914,13 +997,20 @@ cleanup: if (pc->opcode == Op_K_case) { t1 = pp_pop(); fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str); - pc = end_line(pc); pp_free(t1); - } else { + } else fprintf(prof_fp, "%s:", op2str(pc->opcode)); - pc = end_line(pc); - } + indent_in(); + if (pc->comment != NULL) { + if (pc->comment->memory->comment_type == EOL_COMMENT) + fprintf(prof_fp, "\t%s", pc->comment->memory->stptr); + else { + fprintf(prof_fp, "\n"); + print_comment(pc->comment, indent_level); + } + } else + fprintf(prof_fp, "\n"); pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS); indent_out(); break; @@ -937,6 +1027,8 @@ cleanup: fprintf(prof_fp, " # %ld", ip1->exec_count); ip1 = end_line(ip1); indent_in(); + if (pc->comment != NULL) + print_comment(pc->comment, indent_level); pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS); indent_out(); pc = pc->branch_else; @@ -944,7 +1036,7 @@ cleanup: indent(SPACEOVER); fprintf(prof_fp, "}"); if (pc->nexti->nexti->opcode != Op_comment - || pc->nexti->nexti->memory->comment_type == FULL_COMMENT) + || pc->nexti->nexti->memory->comment_type == BLOCK_COMMENT) fprintf(prof_fp, "\n"); /* else It will be printed at the top. */ @@ -980,6 +1072,8 @@ cleanup: end_line(pc); skip_comment = true; indent_in(); + if (pc->comment != NULL) + print_comment(pc->comment, indent_level); pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); @@ -999,6 +1093,9 @@ cleanup: { NODE *f, *t, *cond; size_t len; + INSTRUCTION *qm_comment = NULL, *colon_comment = NULL; + + qm_comment = pc->comment; pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS); ip1 = pc->branch_if; @@ -1006,6 +1103,7 @@ cleanup: ip1 = pc->branch_else->nexti; pc = ip1->nexti; + colon_comment = pc->comment; assert(pc->opcode == Op_cond_exp); pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); @@ -1013,14 +1111,77 @@ cleanup: t = pp_pop(); cond = pp_pop(); - len = f->pp_len + t->pp_len + cond->pp_len + 12; - emalloc(str, char *, len, "pprint"); - sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str); + /* + * This stuff handles comments that come after a ?, :, or both. + * Allowing newlines after ? and : is a gawk extension. + * Theoretically this is fragile, since ?: expressions can be nested. + * In practice, it's not, since if there was a comment following ? or : + * in the original code, then it wasn't nested. + */ + + len = f->pp_len + t->pp_len + cond->pp_len + 12; + if (qm_comment == NULL && colon_comment == NULL) { + // easy case + emalloc(str, char *, len, "pprint"); + sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str); + } else if (qm_comment != NULL && colon_comment != NULL) { + check_indent_level(); + len += qm_comment->memory->stlen + // comments + colon_comment->memory->stlen + + 2 * (indent_level + 1) + 3 + // indentation + t->pp_len + 6; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? comment + "%.*s %s" // indent true-part + " : %s" // : comment + "%.*s %s", // indent false-part + cond->pp_str, // condition + qm_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + t->pp_str, // true part + colon_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + f->pp_str // false part + ); + } else if (qm_comment != NULL) { + check_indent_level(); + len += qm_comment->memory->stlen + // comment + 1 * (indent_level + 1) + 3 + // indentation + t->pp_len + 3; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? comment + "%.*s %s" // indent true-part + " : %s", // : false-part + cond->pp_str, // condition + qm_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + t->pp_str, // true part + f->pp_str // false part + ); + } else { + check_indent_level(); + len += colon_comment->memory->stlen + // comment + 1 * (indent_level + 1) + 3 + // indentation + t->pp_len + 3; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? true-part + " : %s" // : comment + "%.*s %s", // indent false-part + cond->pp_str, // condition + t->pp_str, // true part + colon_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + f->pp_str // false part + ); + } pp_free(cond); pp_free(t); pp_free(f); - pp_push(Op_cond_exp, str, CAN_FREE); + pp_push(Op_cond_exp, str, CAN_FREE, pc->comment); pc = pc->branch_end; } break; @@ -1065,7 +1226,7 @@ end_line(INSTRUCTION *ip) return ret; } -/* pp_string_fp --- printy print a string to the fp */ +/* pp_string_fp --- pretty print a string to the fp */ /* * This routine concentrates string pretty printing in one place, @@ -1124,17 +1285,59 @@ print_lib_list(FILE *prof_fp) { SRCFILE *s; static bool printed_header = false; + const char *indent = ""; + bool found = false; + + if (do_profile) + indent = "\t"; for (s = srcfiles->next; s != srcfiles; s = s->next) { if (s->stype == SRC_EXTLIB) { + if (do_profile && ! printed_header) { + printed_header = true; + fprintf(prof_fp, _("%s# Loaded extensions (-l and/or @load)\n\n"), indent); + } + found = true; + fprintf(prof_fp, "%s@load \"%s\"", indent, s->src); + if (s->comment != NULL) { + fprintf(prof_fp, "\t"); + print_comment(s->comment, indent_level + 1); + } else + fprintf(prof_fp, "\n"); + } + } + if (found) /* we found some */ + fprintf(prof_fp, "\n"); +} + +/* print_include_list --- print a list of all files included */ + +static void +print_include_list(FILE *prof_fp) +{ + SRCFILE *s; + static bool printed_header = false; + bool found = false; + + if (do_profile) + return; + + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if (s->stype == SRC_INC) { if (! printed_header) { printed_header = true; - fprintf(prof_fp, _("\t# Loaded extensions (-l and/or @load)\n\n")); + fprintf(prof_fp, _("\n# Included files (-i and/or @include)\n\n")); } - fprintf(prof_fp, "\t@load \"%s\"\n", s->src); + found = true; + fprintf(prof_fp, "# @include \"%s\"", s->src); + if (s->comment != NULL) { + fprintf(prof_fp, "\t"); + print_comment(s->comment, indent_level + 1); + } else + fprintf(prof_fp, "\n"); } } - if (printed_header) /* we found some */ + if (found) /* we found some */ fprintf(prof_fp, "\n"); } @@ -1158,8 +1361,17 @@ print_comment(INSTRUCTION* pc, long in) after_newline = false; } putc(*text, prof_fp); - if (*text == '\n') - after_newline = true; + after_newline = (*text == '\n'); + } + + if (pc->comment) { + // chaining should only be two deep + assert(pc->comment->comment == NULL); + // if first was EOL comment, next must be block comment, + // it needs to be indented. + if (pc->memory->comment_type == EOL_COMMENT) + in++; + print_comment(pc->comment, in); } } @@ -1181,6 +1393,7 @@ dump_prog(INSTRUCTION *code) fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now)); print_lib_list(prof_fp); pprint(code, NULL, NO_PPRINT_FLAGS); + print_include_list(prof_fp); } /* prec_level --- return the precedence of an operator, for paren tests */ @@ -1535,6 +1748,7 @@ pp_list(int nargs, const char *paren, const char *delim) size_t len; size_t delimlen; int i; + INSTRUCTION *comment = NULL; if (pp_args == NULL) { npp_args = nargs; @@ -1552,12 +1766,17 @@ pp_list(int nargs, const char *paren, const char *delim) for (i = 1; i <= nargs; i++) { r = pp_args[i] = pp_pop(); len += r->pp_len + delimlen; + if (r->pp_comment != NULL) { + comment = (INSTRUCTION *) r->pp_comment; + len += comment->memory->stlen + indent_level + 1; // comment\n ident + } } if (paren != NULL) { assert(strlen(paren) == 2); len += 2; } } + comment = NULL; emalloc(str, char *, len + 1, "pp_list"); s = str; @@ -1573,6 +1792,14 @@ pp_list(int nargs, const char *paren, const char *delim) memcpy(s, delim, delimlen); s += delimlen; } + if (r->pp_comment != NULL) { + check_indent_level(); + comment = (INSTRUCTION *) r->pp_comment; + memcpy(s, comment->memory->stptr, comment->memory->stlen); + s += comment->memory->stlen; + memcpy(s, tabs, indent_level + 1); + s += indent_level + 1; + } r = pp_args[i]; memcpy(s, r->pp_str, r->pp_len); s += r->pp_len; @@ -1731,18 +1958,23 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n")); } + pp_namespace_list(pc[3].nexti); + 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, -1); /* -1 ==> don't indent */ - fp = fp->nexti; - } + if (pc->comment != NULL) + print_comment(pc->comment, -1); /* -1 ==> don't indent */ indent(pc->nexti->exec_count); - fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname); + + bool malloced = false; + char *name = adjust_namespace(func->vname, & malloced); + fprintf(prof_fp, "%s %s(", op2str(Op_K_function), name); + if (malloced) + free(name); pcount = func->param_cnt; func_params = func->fparms; for (j = 0; j < pcount; j++) { @@ -1787,3 +2019,76 @@ redir2str(int redirtype) fatal(_("redir2str: unknown redirection type %d"), redirtype); return redirtab[redirtype]; } + +/* pp_namespace --- print @namespace directive */ + +static void +pp_namespace(const char *name, INSTRUCTION *comment) +{ + // Don't print the initial `@namespace "awk"' unless + // @namespace was used at some point in the program + if (! namespace_changed) + return; + + if (strcmp(current_namespace, name) == 0) + return; + + current_namespace = name; + + if (do_profile) + indent(SPACEOVER); + + fprintf(prof_fp, "@namespace \"%s\"", name); + + if (comment != NULL) { + putc('\t', prof_fp); + print_comment(comment, 0); + putc('\n', prof_fp); + } else + fprintf(prof_fp, "\n\n"); +} + +/* pp_namespace_list --- print the list, back to front, using recursion */ + +static void +pp_namespace_list(INSTRUCTION *list) +{ + if (list == NULL) + return; + + pp_namespace_list(list->nexti); + pp_namespace(list->ns_name, list->comment); +} + +/* adjust_namespace --- remove leading namespace or add leading awk:: */ + +static char * +adjust_namespace(char *name, bool *malloced) +{ + *malloced = false; + + // unadorned name from symbol table, add awk:: if not in awk:: n.s. + if (strchr(name, ':') == NULL && + current_namespace != awk_namespace && // can be equal if namespace never changed + strcmp(current_namespace, "awk") != 0) { + char *buf; + size_t len = 5 + strlen(name) + 1; + + emalloc(buf, char *, len, "adjust_namespace"); + sprintf(buf, "awk::%s", name); + *malloced = true; + + return buf; + } + + // qualifed name, remove <ns>:: if in that n.s. + size_t len = strlen(current_namespace); + + if (strncmp(current_namespace, name, len) == 0) { + char *ret = name + len + 2; + + return ret; + } + + return name; +} diff --git a/str_array.c b/str_array.c index bc6584d2..2fdd1bf2 100644 --- a/str_array.c +++ b/str_array.c @@ -56,10 +56,10 @@ static NODE **str_list(NODE *symbol, NODE *subs); static NODE **str_copy(NODE *symbol, NODE *newsymb); static NODE **str_dump(NODE *symbol, NODE *ndump); -afunc_t str_array_func[] = { +const array_funcs_t str_array_func = { + "str", str_array_init, (afunc_t) 0, - null_length, str_lookup, str_exists, str_clear, @@ -75,10 +75,10 @@ static NODE **env_store(NODE *symbol, NODE *subs); static NODE **env_clear(NODE *symbol, NODE *subs); /* special case for ENVIRON */ -afunc_t env_array_func[] = { +const array_funcs_t env_array_func = { + "env", str_array_init, (afunc_t) 0, - null_length, str_lookup, str_exists, env_clear, @@ -798,7 +798,7 @@ env_clear(NODE *symbol, NODE *subs) environ = NULL; /* ZAP! */ /* str_clear zaps the vtable, reset it */ - symbol->array_funcs = env_array_func; + symbol->array_funcs = & env_array_func; return val; } @@ -831,5 +831,5 @@ init_env_array(NODE *env_node) if (do_posix) return; - env_node->array_funcs = env_array_func; + env_node->array_funcs = & env_array_func; } diff --git a/support/ChangeLog b/support/ChangeLog index a941f28c..9e0ffe71 100644 --- a/support/ChangeLog +++ b/support/ChangeLog @@ -118,6 +118,8 @@ * intprops.h: Sync with GNULIB. * regcomp.c (init_word): Move general_case label inside ifdef. * regex.h: Don't define __USE_GNU. Brings closer to GLIBC regex. + * regex.c: Don't include gawkbool.h, we don't use it anymore. + * dfa.h: Ditto. 2017-11-26 Arnold D. Robbins <arnold@skeeve.com> diff --git a/support/dfa.h b/support/dfa.h index 86902ebf..e419e9a0 100644 --- a/support/dfa.h +++ b/support/dfa.h @@ -19,11 +19,7 @@ /* Written June, 1988 by Mike Haertel */ #include <regex.h> -#ifdef HAVE_STDBOOL_H #include <stdbool.h> -#else -#include "missing_d/gawkbool.h" -#endif /* HAVE_STDBOOL_H */ #include <stddef.h> #if 3 <= __GNUC__ @@ -39,6 +39,7 @@ static void (*install_func)(NODE *) = NULL; static NODE *make_symbol(const char *name, NODETYPE type); static NODE *install(const char *name, NODE *parm, NODETYPE type); static void free_bcpool(INSTRUCTION_POOL *pl); +static const char *fix_up_namespace(const char *name, bool *malloced); static AWK_CONTEXT *curr_ctxt = NULL; static int ctxt_level; @@ -88,12 +89,13 @@ install_symbol(const char *name, NODETYPE type) */ NODE * -lookup(const char *name) +lookup(const char *name, bool do_qualify) { NODE *n; NODE *tmp; NODE *tables[5]; /* manual init below, for z/OS */ int i; + bool malloced = false; /* ``It's turtles, all the way down.'' */ tables[0] = param_table; /* parameters shadow everything */ @@ -102,11 +104,17 @@ lookup(const char *name) tables[3] = symbol_table; /* then globals */ tables[4] = NULL; - tmp = make_string(name, strlen(name)); + if (do_qualify) + name = fix_up_namespace(name, & malloced); + + if (malloced) + tmp = make_str_node(name, strlen(name), ALREADY_MALLOCED); + else + tmp = make_string(name, strlen(name)); n = NULL; for (i = 0; tables[i] != NULL; i++) { - if (tables[i]->table_size == 0) + if (assoc_empty(tables[i])) continue; if ((do_posix || do_traditional) && tables[i] == global_table) @@ -303,8 +311,19 @@ install(const char *name, NODE *parm, NODETYPE type) NODE *table; NODE *n_name; NODE *prev; + bool malloced = false; + + if (type == Node_param_list) { + n_name = make_string(name, strlen(name)); + } else { + name = fix_up_namespace(name, & malloced); + + if (malloced) + n_name = make_str_node(name, strlen(name), ALREADY_MALLOCED); + else + n_name = make_string(name, strlen(name)); + } - n_name = make_string(name, strlen(name)); table = symbol_table; if (type == Node_param_list) { @@ -644,7 +663,7 @@ check_param_names(void) bool result = true; NODE n; - if (func_table->table_size == 0) + if (assoc_empty(func_table)) return result; max = func_table->table_size * 2; @@ -946,3 +965,62 @@ free_bcpool(INSTRUCTION_POOL *pl) for (i = 0; i < MAX_INSTRUCTION_ALLOC; i++) free_bc_mempool(& pl->pool[i], i + 1); } + +/* is_all_upper --- return true if name is all uppercase letters */ + +static bool +is_all_upper(const char *name) +{ + for (; *name != '\0'; name ++) { + switch (*name) { + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + break; + default: + return false; + } + } + + return true; +} + +/* fix_up_namespace --- qualify / dequalify a simple name */ + +static const char * +fix_up_namespace(const char *name, bool *malloced) +{ + static char awk_ns[] = "awk::"; + const size_t awk_ns_len = sizeof(awk_ns) - 1; // don't include trailing \0 + char *cp; + + assert(malloced != NULL); + *malloced = false; + + // first, check if it's qualified + if ((cp = strchr(name, ':')) != NULL) { + // does it start with awk:: ? + if (strncmp(name, awk_ns, awk_ns_len) == 0) + return cp + 2; // just trailing part + + // otherwise it's fully qualified, not in the awk n.s. + return name; + } + + // not fully qualified + if (current_namespace == awk_namespace || is_all_upper(name)) + return name; // put it into awk namespace + + // make it fully qualified + size_t len = strlen(current_namespace) + 2 + strlen(name) + 1; + char *buf = NULL; + + emalloc(buf, char *, len, "fix_up_namespace"); + sprintf(buf, "%s::%s", current_namespace, name); + *malloced = true; + + return buf; +} diff --git a/test/ChangeLog b/test/ChangeLog index 69cedf65..812f3faf 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,8 @@ +2019-01-09 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (EXTRA_DIST): New test: arraytype. + * arraytype.awk, arraytype.ok: New files. + 2018-12-24 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (inetdayt, inetdayu, inetecht, inetechu): Add @@ -12,12 +17,41 @@ * Makefile.am (EXTRA_DIST): New test: dfacheck1. * dfacheck1.awk, dfacheck1.in, dfacheck1.ok: New files. +2018-12-12 Arnold D. Robbins <arnold@skeeve.com> + + * nsprof2.awk: Add extra @namespace lines for testing. + * nsprof2.ok: Adjusted. + +2018-12-06 Arnold D. Robbins <arnold@skeeve.com> + + * nsprof2.awk, nsprof2.ok: Updated after code changes. + +2018-11-28 Arnold D. Robbins <arnold@skeeve.com> + + * profile11.ok: Updated after code change. + +2018-11-27 Arnold D. Robbins <arnold@skeeve.com> + + * profile11.awk: Disambiguate some comments. + * profile5.ok, profile11.ok: Updated after code change. + +2018-11-26 Arnold D. Robbins <arnold@skeeve.com> + + * profile5.ok: Updated after code change. + * Makefile.am (GAWK_EXT_TESTS): New test, profile11.ok. Add + to the other relevant macros. + * profile11.awk, profile11.ok: New files. + 2018-11-25 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (GAWK_EXT_TESTS): Fix layout of the list. 2018-11-24 Arnold D. Robbins <arnold@skeeve.com> + * profile5.ok: Updated after code change. + +2018-11-24 Arnold D. Robbins <arnold@skeeve.com> + * spacere.awk: Move setting of LC_ALL=C out to ... * Makefile.am (spacere): ... here. Added test. Per request from Eli Zaretskii to help porting to MinGW. @@ -27,6 +61,14 @@ * Makefile.am (EXTRA_DIST): New test: typedregex4. * typedregex4.awk, typedregex4.ok: New files. +2018-11-11 Arnold D. Robbins <arnold@skeeve.com> + + * profile10.ok: Updated after code change. + +2018-10-14 Arnold D. Robbins <arnold@skeeve.com> + + * profile0.ok: Updated after code change. + 2018-10-10 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (profile1): Add minus to ignore errors on final @@ -455,6 +497,40 @@ * inplace1.ok, inplace2.ok, inplace3.ok: Update after adding license to inplace.awk. +2017-07-26 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (nsbad_cmd, nsindirect1, nsindirect2): New tests. + * nsbad_cmd.ok, nsindirect1.awk, nsindirect1.ok, nsindirect2.awk, + nsindirect2.ok: New files. + +2017-07-26 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (nsbad): New test. + * nsbad.awk, nsbad.ok: New files. + +2017-07-20 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (inplace1, inplace2, inplace3): Update to use + inplace::suffix instead of INPLACE_SUFFIX. + * inplace1.ok, inplace2.ok, inplace3.ok: Update after code + changes. + +2017-07-07 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (eofsrc1): New test. + * eofsrc1a.awk, eofsrc1b.awk, eofsrc1.ok: New files. + * unterm.ok: Updated after code change. + +2017-07-01 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (nsprof2): New test. + * nsprof2.awk, nsprof2.ok: New files. + +2017-06-30 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (nsprof1): New test. + * nsprof1.awk, nsprof1.ok: New files. + 2017-06-27 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (mbprintf5): Skip this test on Cygwin. @@ -469,6 +545,10 @@ * Makefile.am (mbprintf5): New test. * mbprintf5.awk, mbprintf5.in, mbprintf5.ok: New files. +2017-05-30 Arnold D. Robbins <arnold@skeeve.com> + + * sourceplit.ok: Revise to match changed code. + 2017-05-24 Andrew J. Schorr <aschorr@telemetry-investments.com> * fwtest8.ok: Fix field number in error message, thanks to a bug diff --git a/test/Makefile.am b/test/Makefile.am index c6b8caeb..0ffad9ad 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -76,6 +76,8 @@ EXTRA_DIST = \ arraysort.ok \ arraysort2.awk \ arraysort2.ok \ + arraytype.awk \ + arraytype.ok \ arrdbg.awk \ arrymem1.awk \ arrymem1.ok \ @@ -260,6 +262,9 @@ EXTRA_DIST = \ dynlj.ok \ eofsplit.awk \ eofsplit.ok \ + eofsrc1a.awk \ + eofsrc1b.awk \ + eofsrc1.ok \ errno.awk \ errno.in \ errno.ok \ @@ -765,6 +770,17 @@ EXTRA_DIST = \ noparms.ok \ nors.in \ nors.ok \ + nsbad.awk \ + nsbad.ok \ + nsbad_cmd.ok \ + nsindirect1.awk \ + nsindirect1.ok \ + nsindirect2.awk \ + nsindirect2.ok \ + nsprof1.awk \ + nsprof1.ok \ + nsprof2.awk \ + nsprof2.ok \ nulinsrc.awk \ nulinsrc.ok \ nulrsend.awk \ @@ -902,6 +918,8 @@ EXTRA_DIST = \ profile9.ok \ profile10.awk \ profile10.ok \ + profile11.awk \ + profile11.ok \ prt1eval.awk \ prt1eval.ok \ prtoeval.awk \ @@ -1254,10 +1272,10 @@ BASIC_TESTS = \ callparam childin clobber closebad clsflnam compare compare2 \ concat1 concat2 concat3 concat4 concat5 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ - eofsplit exit2 exitval1 exitval2 exitval3 fcall_exit fcall_exit2 \ - fldchg fldchgnf fldterm fnamedat fnarray fnarray2 fnaryscl fnasgnm fnmisc \ - fordel forref forsimp fsbs fsnul1 fsrs fsspcoln fstabplus funsemnl \ - funsmnam funstack \ + eofsplit eofsrc1 exit2 exitval1 exitval2 exitval3 \ + fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \ + fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \ + fstabplus funsemnl funsmnam funstack \ getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \ gsubasgn gsubtest gsubtst2 gsubtst3 gsubtst4 gsubtst5 gsubtst6 gsubtst7 \ gsubtst8 \ @@ -1292,6 +1310,7 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort arraysort2 \ + arraytype \ backw badargs beginfile1 beginfile2 binmode1 \ charasbytes colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \ clos1way6 crlf \ @@ -1306,19 +1325,20 @@ GAWK_EXT_TESTS = \ incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \ indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \ - mixed1 mktime manyfiles match1 match2 match3 mbstr1 mbstr2 muldimposix \ + manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \ nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \ + nsbad nsbad_cmd nsindirect1 nsindirect2 nsprof1 nsprof2 \ patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge \ procinfs profile0 profile1 profile2 profile3 profile4 profile5 profile6 \ - profile7 profile8 profile9 profile10 pty1 pty2 \ + profile7 profile8 profile9 profile10 profile11 pty1 pty2 \ rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin \ rsstart1 rsstart2 rsstart3 rstest6 \ shadow shadowbuiltin sortfor sortfor2 sortu sourcesplit split_after_fpat \ - splitarg4 strftime strftfld strtonum strtonum1 switch2 symtab1 symtab2 \ + splitarg4 strftfld strftime strtonum strtonum1 switch2 symtab1 symtab2 \ symtab3 symtab4 symtab5 symtab6 symtab7 symtab8 symtab9 symtab10 \ - typedregex1 typedregex2 typedregex3 typedregex4 \ + timeout typedregex1 typedregex2 typedregex3 typedregex4 \ typeof1 typeof2 typeof3 typeof4 typeof5 \ - timeout watchpoint1 + watchpoint1 ARRAYDEBUG_TESTS = arrdbg @@ -1367,7 +1387,8 @@ NEED_NONDEC = mpfrbigint2 nondec2 intarray forcenum NEED_POSIX = printf0 posix2008sub paramasfunc1 paramasfunc2 muldimposix # List of tests that need --pretty-print -NEED_PRETTY = profile4 profile5 profile8 profile9 profile10 +NEED_PRETTY = nsprof1 nsprof2 \ + profile4 profile5 profile8 profile9 profile10 profile11 # List of tests that need --re-interval NEED_RE_INTERVAL = gsubtst3 reint reint2 @@ -2026,7 +2047,7 @@ inplace2:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -2037,8 +2058,8 @@ inplace3:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -2104,8 +2125,7 @@ charasbytes: symtab6: @echo $@ - @$(AWK) -d__$@ -f "$(srcdir)"/$@.awk - @grep -v '^ENVIRON' __$@ | grep -v '^PROCINFO' > _$@ ; rm __$@ + @$(AWK) -f "$(srcdir)"/$@.awk > _$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ symtab8: @@ -2195,6 +2215,17 @@ sourcesplit: @AWKPATH="$(srcdir)" $(AWK) --source='BEGIN { a = 5;' --source='print a }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +eofsrc1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f "$(srcdir)"/$@a.awk -f "$(srcdir)"/$@b.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsbad_cmd: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -v foo:bar=3 -v foo:::blat=4 1 /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + + # Use [:] in the regexp to keep MSYS from converting the /'s to \'s. nonfatal1: @echo $@ diff --git a/test/Makefile.in b/test/Makefile.in index c95a1dc8..c244c7af 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -334,6 +334,8 @@ EXTRA_DIST = \ arraysort.ok \ arraysort2.awk \ arraysort2.ok \ + arraytype.awk \ + arraytype.ok \ arrdbg.awk \ arrymem1.awk \ arrymem1.ok \ @@ -518,6 +520,9 @@ EXTRA_DIST = \ dynlj.ok \ eofsplit.awk \ eofsplit.ok \ + eofsrc1a.awk \ + eofsrc1b.awk \ + eofsrc1.ok \ errno.awk \ errno.in \ errno.ok \ @@ -1023,6 +1028,17 @@ EXTRA_DIST = \ noparms.ok \ nors.in \ nors.ok \ + nsbad.awk \ + nsbad.ok \ + nsbad_cmd.ok \ + nsindirect1.awk \ + nsindirect1.ok \ + nsindirect2.awk \ + nsindirect2.ok \ + nsprof1.awk \ + nsprof1.ok \ + nsprof2.awk \ + nsprof2.ok \ nulinsrc.awk \ nulinsrc.ok \ nulrsend.awk \ @@ -1160,6 +1176,8 @@ EXTRA_DIST = \ profile9.ok \ profile10.awk \ profile10.ok \ + profile11.awk \ + profile11.ok \ prt1eval.awk \ prt1eval.ok \ prtoeval.awk \ @@ -1512,10 +1530,10 @@ BASIC_TESTS = \ callparam childin clobber closebad clsflnam compare compare2 \ concat1 concat2 concat3 concat4 concat5 convfmt \ datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \ - eofsplit exit2 exitval1 exitval2 exitval3 fcall_exit fcall_exit2 \ - fldchg fldchgnf fldterm fnamedat fnarray fnarray2 fnaryscl fnasgnm fnmisc \ - fordel forref forsimp fsbs fsnul1 fsrs fsspcoln fstabplus funsemnl \ - funsmnam funstack \ + eofsplit eofsrc1 exit2 exitval1 exitval2 exitval3 \ + fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \ + fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \ + fstabplus funsemnl funsmnam funstack \ getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \ gsubasgn gsubtest gsubtst2 gsubtst3 gsubtst4 gsubtst5 gsubtst6 gsubtst7 \ gsubtst8 \ @@ -1550,6 +1568,7 @@ UNIX_TESTS = \ GAWK_EXT_TESTS = \ aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort arraysort2 \ + arraytype \ backw badargs beginfile1 beginfile2 binmode1 \ charasbytes colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \ clos1way6 crlf \ @@ -1564,19 +1583,20 @@ GAWK_EXT_TESTS = \ incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \ indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \ - mixed1 mktime manyfiles match1 match2 match3 mbstr1 mbstr2 muldimposix \ + manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \ nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \ + nsbad nsbad_cmd nsindirect1 nsindirect2 nsprof1 nsprof2 \ patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge \ procinfs profile0 profile1 profile2 profile3 profile4 profile5 profile6 \ - profile7 profile8 profile9 profile10 pty1 pty2 \ + profile7 profile8 profile9 profile10 profile11 pty1 pty2 \ rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin \ rsstart1 rsstart2 rsstart3 rstest6 \ shadow shadowbuiltin sortfor sortfor2 sortu sourcesplit split_after_fpat \ - splitarg4 strftime strftfld strtonum strtonum1 switch2 symtab1 symtab2 \ + splitarg4 strftfld strftime strtonum strtonum1 switch2 symtab1 symtab2 \ symtab3 symtab4 symtab5 symtab6 symtab7 symtab8 symtab9 symtab10 \ - typedregex1 typedregex2 typedregex3 typedregex4 \ + timeout typedregex1 typedregex2 typedregex3 typedregex4 \ typeof1 typeof2 typeof3 typeof4 typeof5 \ - timeout watchpoint1 + watchpoint1 ARRAYDEBUG_TESTS = arrdbg EXTRA_TESTS = inftest regtest ignrcas3 @@ -1624,7 +1644,8 @@ NEED_NONDEC = mpfrbigint2 nondec2 intarray forcenum NEED_POSIX = printf0 posix2008sub paramasfunc1 paramasfunc2 muldimposix # List of tests that need --pretty-print -NEED_PRETTY = profile4 profile5 profile8 profile9 profile10 +NEED_PRETTY = nsprof1 nsprof2 \ + profile4 profile5 profile8 profile9 profile10 profile11 # List of tests that need --re-interval NEED_RE_INTERVAL = gsubtst3 reint reint2 @@ -2474,7 +2495,7 @@ inplace2:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -2485,8 +2506,8 @@ inplace3:: @echo $@ @cp "$(srcdir)"/inplace.1.in _$@.1 @cp "$(srcdir)"/inplace.2.in _$@.2 - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @AWKPATH="$(srcdir)"/../awklib/eg/lib $(AWK) -i inplace -v inplace::suffix=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _$@.1 - _$@.2 < "$(srcdir)"/inplace.in >>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ @-$(CMP) "$(srcdir)"/$@.1.ok _$@.1 && rm -f _$@.1 @-$(CMP) "$(srcdir)"/$@.1.bak.ok _$@.1.bak && rm -f _$@.1.bak @@ -2552,8 +2573,7 @@ charasbytes: symtab6: @echo $@ - @$(AWK) -d__$@ -f "$(srcdir)"/$@.awk - @grep -v '^ENVIRON' __$@ | grep -v '^PROCINFO' > _$@ ; rm __$@ + @$(AWK) -f "$(srcdir)"/$@.awk > _$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ symtab8: @@ -2641,6 +2661,16 @@ sourcesplit: @AWKPATH="$(srcdir)" $(AWK) --source='BEGIN { a = 5;' --source='print a }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +eofsrc1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f "$(srcdir)"/$@a.awk -f "$(srcdir)"/$@b.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsbad_cmd: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -v foo:bar=3 -v foo:::blat=4 1 /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + # Use [:] in the regexp to keep MSYS from converting the /'s to \'s. nonfatal1: @echo $@ @@ -3944,6 +3974,11 @@ arraysort2: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +arraytype: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + backw: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4276,11 +4311,6 @@ lintwarn: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -mktime: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - match1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4308,6 +4338,11 @@ mbstr2: AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mktime: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + muldimposix: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4343,6 +4378,31 @@ nonfatal3: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +nsbad: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + patsplit: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4404,6 +4464,11 @@ profile10: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +profile11: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + regnul1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4540,6 +4605,11 @@ symtab10: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +timeout: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + typedregex1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4580,11 +4650,6 @@ typeof5: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -timeout: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - double1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 05804988..7163b4ab 100644 --- a/test/Maketests +++ b/test/Maketests @@ -1269,6 +1269,11 @@ arraysort2: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +arraytype: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + backw: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1601,11 +1606,6 @@ lintwarn: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -mktime: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - match1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1633,6 +1633,11 @@ mbstr2: AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mktime: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + muldimposix: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1668,6 +1673,31 @@ nonfatal3: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +nsbad: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsindirect2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +nsprof2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + patsplit: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1729,6 +1759,11 @@ profile10: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +profile11: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --pretty-print=_$@ >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + regnul1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1865,6 +1900,11 @@ symtab10: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +timeout: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + typedregex1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1905,11 +1945,6 @@ typeof5: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ -timeout: - @echo $@ - @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ - double1: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/arraytype.awk b/test/arraytype.awk new file mode 100644 index 00000000..70fd72b0 --- /dev/null +++ b/test/arraytype.awk @@ -0,0 +1,35 @@ +BEGIN { + # N.B. This relies upon the undocumented 2nd argument to typeof + x[0] = 0 + print typeof(x, a) + print a["array_type"] + + # make sure it resets + delete x[0] + print typeof(x, a) + print a["array_type"] + + x["fubar"] = 0 + print typeof(x, a) + print a["array_type"] + + delete x["fubar"] + print typeof(x, a) + print a["array_type"] + + x[-2] = 0 + print typeof(x, a) + print a["array_type"] + + delete x[-2] + print typeof(x, a) + print a["array_type"] + + x[2] = 0 + print typeof(x, a) + print a["array_type"] + + delete x + print typeof(x, a) + print a["array_type"] +} diff --git a/test/arraytype.ok b/test/arraytype.ok new file mode 100644 index 00000000..6595bb89 --- /dev/null +++ b/test/arraytype.ok @@ -0,0 +1,16 @@ +array +cint +array +null +array +str +array +null +array +int +array +null +array +cint +array +null diff --git a/test/eofsrc1.ok b/test/eofsrc1.ok new file mode 100644 index 00000000..64d85b33 --- /dev/null +++ b/test/eofsrc1.ok @@ -0,0 +1,3 @@ +gawk: ./eofsrc1a.awk:2: (END OF FILE) +gawk: ./eofsrc1a.awk:2: ^ source files / command-line arguments must contain complete functions or rules +EXIT CODE: 1 diff --git a/test/eofsrc1a.awk b/test/eofsrc1a.awk new file mode 100644 index 00000000..55143c2b --- /dev/null +++ b/test/eofsrc1a.awk @@ -0,0 +1,2 @@ +BEGIN { + n = 5 diff --git a/test/eofsrc1b.awk b/test/eofsrc1b.awk new file mode 100644 index 00000000..0dad2163 --- /dev/null +++ b/test/eofsrc1b.awk @@ -0,0 +1,2 @@ + print n +} diff --git a/test/inplace1.ok b/test/inplace1.ok index 730d7754..753079b3 100644 --- a/test/inplace1.ok +++ b/test/inplace1.ok @@ -1,5 +1,5 @@ before -gawk: inplace:47: warning: inplace_begin: disabling in-place editing for invalid FILENAME `-' +gawk: inplace:53: warning: inplace::begin: disabling in-place editing for invalid FILENAME `-' stdin start is bar replaced? stdin end diff --git a/test/inplace2.ok b/test/inplace2.ok index 730d7754..753079b3 100644 --- a/test/inplace2.ok +++ b/test/inplace2.ok @@ -1,5 +1,5 @@ before -gawk: inplace:47: warning: inplace_begin: disabling in-place editing for invalid FILENAME `-' +gawk: inplace:53: warning: inplace::begin: disabling in-place editing for invalid FILENAME `-' stdin start is bar replaced? stdin end diff --git a/test/inplace3.ok b/test/inplace3.ok index 815cd1c7..7802a0c8 100644 --- a/test/inplace3.ok +++ b/test/inplace3.ok @@ -1,11 +1,11 @@ before -gawk: inplace:47: warning: inplace_begin: disabling in-place editing for invalid FILENAME `-' +gawk: inplace:53: warning: inplace::begin: disabling in-place editing for invalid FILENAME `-' stdin start is bar replaced? stdin end after Before -gawk: inplace:47: warning: inplace_begin: disabling in-place editing for invalid FILENAME `-' +gawk: inplace:53: warning: inplace::begin: disabling in-place editing for invalid FILENAME `-' stdin start is foo replaced? stdin end diff --git a/test/nsbad.awk b/test/nsbad.awk new file mode 100644 index 00000000..825bb35c --- /dev/null +++ b/test/nsbad.awk @@ -0,0 +1,15 @@ +@namespace "1foo" +@namespace "for" +@namespace "42f" +@namespace "ab#d" + +BEGIN { + foo75::bar = 57 + if::junk = 1 + foo::match = 3 +} + +@namespace "foo" +function gsub () { + print "foo::gsub" +} diff --git a/test/nsbad.ok b/test/nsbad.ok new file mode 100644 index 00000000..dfa228a7 --- /dev/null +++ b/test/nsbad.ok @@ -0,0 +1,13 @@ +gawk: nsbad.awk:1: error: namespace name `1foo' must meet identifier naming rules +gawk: nsbad.awk:2: error: using reserved identifier `for' as a namespace is not allowed +gawk: nsbad.awk:3: error: namespace name `42f' must meet identifier naming rules +gawk: nsbad.awk:4: error: namespace name `ab#d' must meet identifier naming rules +gawk: nsbad.awk:8: error: using reserved identifier `if' as a namespace is not allowed +gawk: nsbad.awk:8: if::junk = 1 +gawk: nsbad.awk:8: ^ syntax error +gawk: nsbad.awk:9: error: using reserved identifier `match' as second component of a qualified name is not allowed +gawk: nsbad.awk:9: foo::match = 3 +gawk: nsbad.awk:9: ^ syntax error +gawk: nsbad.awk:13: function gsub () { +gawk: nsbad.awk:13: ^ `gsub' is a built-in function, it cannot be redefined +EXIT CODE: 1 diff --git a/test/nsbad_cmd.ok b/test/nsbad_cmd.ok new file mode 100644 index 00000000..cbca6ea0 --- /dev/null +++ b/test/nsbad_cmd.ok @@ -0,0 +1,3 @@ +gawk: error: identifier foo:bar: namespace separator is two colons, not one +gawk: error: qualified identifier `foo:::blat' is badly formed +EXIT CODE: 1 diff --git a/test/nsindirect1.awk b/test/nsindirect1.awk new file mode 100644 index 00000000..d04863f5 --- /dev/null +++ b/test/nsindirect1.awk @@ -0,0 +1,13 @@ +@namespace "test" + +BEGIN { + bar = 3 +} + +@namespace "awk" + +BEGIN { + print "before change, direct =", test::bar, "indirect =", SYMTAB["test::bar"] + SYMTAB["test::bar"] = 4 + print "after change, direct =", test::bar, "indirect =", SYMTAB["test::bar"] +} diff --git a/test/nsindirect1.ok b/test/nsindirect1.ok new file mode 100644 index 00000000..ab2e31ba --- /dev/null +++ b/test/nsindirect1.ok @@ -0,0 +1,2 @@ +before change, direct = 3 indirect = 3 +after change, direct = 4 indirect = 4 diff --git a/test/nsindirect2.awk b/test/nsindirect2.awk new file mode 100644 index 00000000..8017e8f7 --- /dev/null +++ b/test/nsindirect2.awk @@ -0,0 +1,44 @@ +BEGIN { + stftime::gensub = 3 # should be OK, not related to indirect calls +} + + +BEGIN { base_time = systime() } # in awk namespace + +@namespace "testing" + +function strftime(mesg) +{ + printf("strftime(%s) - this is not the function you are looking for\n", + mesg) + return 0 +} + +BEGIN { + strftime("from 'testing'") + gensub = "gensub" + print "gensub =", gensub +} + +function systime() +{ + return awk::base_time +} + +BEGIN { + st = "systime" + now[1] = @st() + + st = "awk::systime" + now[2] = @st() + + st = "testing::systime" + now[3] = @st() + + for (i = 1; i <= 3; i++) { + if (now[i] == awk::base_time || now[i] == awk::base_time + 1) + printf "iteration %d, got good result from systime\n", i + else + printf "iteration %d, got bad result from systime, now %d, base_time %d\n", i, now, awk::base_time + } +} diff --git a/test/nsindirect2.ok b/test/nsindirect2.ok new file mode 100644 index 00000000..9b71cd92 --- /dev/null +++ b/test/nsindirect2.ok @@ -0,0 +1,5 @@ +strftime() - this is not the function you are looking for +gensub = gensub +iteration 1, got good result from systime +iteration 2, got good result from systime +iteration 3, got good result from systime diff --git a/test/nsprof1.awk b/test/nsprof1.awk new file mode 100644 index 00000000..46be5bc9 --- /dev/null +++ b/test/nsprof1.awk @@ -0,0 +1,16 @@ +@namespace "foo" + +BEGIN { + a = 5 + a++ + print a +} + +/foo/ { print "bar" } + +@namespace "stuff" + +function stuff() +{ + print "stuff" +} diff --git a/test/nsprof1.ok b/test/nsprof1.ok new file mode 100644 index 00000000..eacc2707 --- /dev/null +++ b/test/nsprof1.ok @@ -0,0 +1,19 @@ +@namespace "foo" + +BEGIN { + a = 5 + a++ + print a +} + +/foo/ { + print "bar" +} + +@namespace "stuff" + + +function stuff() +{ + print "stuff" +} diff --git a/test/nsprof2.awk b/test/nsprof2.awk new file mode 100644 index 00000000..9c7da57e --- /dev/null +++ b/test/nsprof2.awk @@ -0,0 +1,74 @@ +# passwd.awk --- access password file information +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 +# Revised July 2017 + +@namespace "foo" # this is foo + +@namespace "bar" # this is bar + +@namespace "passwd" # move to passwd namespace + +BEGIN { + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" +} + +function Init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +{ + if (Inited) + return + + oldfs = FS + oldrs = RS + olddol0 = $0 + using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (PROCINFO["FS"] == "FPAT") + FS = ":" + RS = "\n" + + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) { + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + } + close(pwcat) + Count = 0 + Inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +} + +function awk::getpwnam(name) +{ + Init() + return Byname[name] +} + +function awk::getpwuid(uid) +{ + Init() + return Byuid[uid] +} + +function awk::getpwent() +{ + Init() + if (Count < Total) + return Bycount[++Count] + return "" +} + +function awk::endpwent() +{ + Count = 0 +} diff --git a/test/nsprof2.ok b/test/nsprof2.ok new file mode 100644 index 00000000..1bb78822 --- /dev/null +++ b/test/nsprof2.ok @@ -0,0 +1,75 @@ +# passwd.awk --- access password file information +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 +# Revised July 2017 +@namespace "foo" # this is foo + +@namespace "bar" # this is bar + +@namespace "passwd" # move to passwd namespace + +BEGIN { + # tailor this to suit your system + Awklib = "/usr/local/libexec/awk/" +} + + +function awk::endpwent() +{ + Count = 0 +} + +function awk::getpwent() +{ + Init() + if (Count < Total) { + return Bycount[++Count] + } + return "" +} + +function awk::getpwnam(name) +{ + Init() + return Byname[name] +} + +function awk::getpwuid(uid) +{ + Init() + return Byuid[uid] +} + +function Init(oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +{ + if (Inited) { + return + } + oldfs = awk::FS + oldrs = awk::RS + olddol0 = $0 + using_fw = (awk::PROCINFO["FS"] == "FIELDWIDTHS") + using_fpat = (awk::PROCINFO["FS"] == "FPAT") + awk::FS = ":" + awk::RS = "\n" + pwcat = Awklib "pwcat" + while ((pwcat | getline) > 0) { + Byname[$1] = $0 + Byuid[$3] = $0 + Bycount[++Total] = $0 + } + close(pwcat) + Count = 0 + Inited = 1 + awk::FS = oldfs + if (using_fw) { + awk::FIELDWIDTHS = awk::FIELDWIDTHS + } else if (using_fpat) { + awk::FPAT = awk::FPAT + } + awk::RS = oldrs + $0 = olddol0 +} diff --git a/test/profile0.ok b/test/profile0.ok index 2e3c5728..42c464ba 100644 --- a/test/profile0.ok +++ b/test/profile0.ok @@ -1,6 +1,6 @@ # Rule(s) 2 NR == 1 { # 1 - 1 print $0 + 1 print } diff --git a/test/profile10.ok b/test/profile10.ok index 13f0b67b..0f77bd38 100644 --- a/test/profile10.ok +++ b/test/profile10.ok @@ -17,14 +17,12 @@ BEGIN { # Comment 0 print "MNO" # Comment 16 } # Comment 17 switch (q) { - case "a": - # Comment 18 + # Comment 18 + case "a": # Comment 19 case "b": - # Comment 19 - break # Comment 20 - # Comment 21 - default: - # Comment 22 + # Comment 20 + break # Comment 21 + default: # Comment 22 break # Comment 23 } # Comment 24 diff --git a/test/profile11.awk b/test/profile11.awk new file mode 100644 index 00000000..06ede8ac --- /dev/null +++ b/test/profile11.awk @@ -0,0 +1,321 @@ + +# comments/for.awk +BEGIN { + for (i = 1; i <= 10; i++) print i + + for (i = 1; i <= 10; i++) # comment 0 + print i + + for (i = 1; # comment 1a + i <= 10; i++) print i + + for (i = 1; i <= 10; # comment 2a + i++) print i + + for (i = 1; # comment 1b + i <= 10; # comment 2b + i++) print i + + for (i = 1; # comment 1c + i <= 10; # comment 2c + i++) # comment 3c + print i +} + +# comments/for0.awk +BEGIN { + for (iggy in foo) # comment 5 + # comment 6 + ; +} + +# comments/for1.awk +BEGIN { + for (iggy in foo) # comment 1 + # comment 2 + { + print iggy + } + + for (iggy in foo) # comment 3 + # comment 4 + print iggy + + for (iggy in foo) # comment 5 + # comment 6 + ; +} + +# comments/for2.awk +BEGIN { + for (;;) print i + + for (;;) # comment 0 + print i + + for (; # comment 1a + ;) print i + + for (; ; # comment 2a + ) print i + + for (; # comment 1b + ; # comment 2b + ) print i + + for (; # comment 1c + ; # comment 2c + ) # comment 3c + print i +} + +# comments/for_del.awk +BEGIN { for (iggy in foo) delete foo[iggy] } + +# comments/do.awk +BEGIN { + do # DO comment + { # LBRACE comment + # block comment + print 42 + } # rbrace comment + while (0) # WHILE comment +} + +# comments/do2.awk +BEGIN { + do # DO comment + { # LBRACE comment + # block comment + print 42 + } # rbrace comment + while (0) +} + +# comments2/do.awk +BEGIN { + do # do comment + { # lbrace comment + # block comment + print 42 + } # rbace EOL comment + # rbrace block comment + while (1) # while comment +} + +# comments2/if.awk +BEGIN { + if (a) # IF comment + print "foo" # print comment + + if (a) # IF comment 2 + { # lbrace comment + print "bar" + } + else # ELSE comment + print "baz" +} + +# comments/if0.awk +BEGIN { + if (a) + ; # nothing + else + print "b" +} + +# comments/switch.awk +BEGIN { + a = 5 + switch (a) # switch EOL comment + # switch block comment + { # lbrace EOL comment + # lbrace block comment + case 5: # comment after case + print "five!" + break + # block comment after case + default: # comment after default + print "default" # print comment + break + } # rbrace EOL comment + # rbrace block comment +} + +# comments2/switch.awk +BEGIN { + a = 5 + switch (a) # switch EOL comment + # switch block comment + { # lbrace EOL comment + # lbrace block comment + case 5: + print "five!" + break; + # block comment after case + } # rbrace EOL comment + # rbrace block comment +} + +# comments2/switch0.awk +BEGIN { + a = 5 + switch (a) + { + case 5: # case comment + print "five!" + break + default: # default comment + print "default" + break + } +} + +# comments2/switch1.awk +BEGIN { + a = 5 + switch (a) + { + case 5: + # case comment + print "five!" + break + default: # default comment + print "default" + break + } +} + +# comments2/while.awk +BEGIN { + while (1) # while comment + { # lbrace comment + # block comment + print 42 + } +} + +# comments2/while2.awk +BEGIN { + while (1) # while comment + { # lbrace comment + # block comment + } +} + +# comments2/f.awk +function bar(p1, + p2) +{ + print "foo" +} # rbrace eol bar + # rbrace block bar + +# comments2/function.awk +function baz(p1, # comment + p2) + # comment before braces +{ # lbrace eol + # lbrace block + print "foo" +} # rbrace eol baz + # rbrace block baz + +# comments/function.awk +function funny(param1, # param comment 1 + param2, param3, # param comment 2 + param4) + # Comment between header and body +{ # lbrace EOL comment + # lbrace block comment + print "funny" +} # rbrace EOL comment funny + # rbrace block comment funny + +# comments/function2.awk +function funnyhaha(param1, + param2, param3, + param4) +{ # lbrace EOL comment + # lbrace block comment + print "funny" +} # rbrace EOL comment funnyhaha + # rbrace block comment funnyhaha + +# comments/callcoma.awk +function callme(a, b, c) +{ + printf("a = %s, b = %s, c = %s\n", # format comment + a, # a2 comment + b, # b2 comment + c) +} + +BEGIN { + callme(1, # 1 comment + 2, # 2 comment + 3) +} + +# comments/exp.awk +/foo/, # range comment + # range comment 2 + +# range comment b + +# range comment c +/bar/ { print } + +# comments/load.awk +@load "filefuncs" # get file functions + +BEGIN { + stat("/etc/passwd", data) + for (i in data) + print i, data[i] +} + +# comments/andor.awk +BEGIN { + if (a && # and comment + b || # or comment + c) + print "foo" +} + +# comments/qmcol-qm.awk +BEGIN { + a = 1 ? # qm comment + 2 : + 3 + print a +} + +# comments/qmcol-colon.awk +BEGIN { + a = 1 ? + 2 : # colon comment + 3 + print a +} + +# comments/qmcolboth.awk +BEGIN { + a = 1 ? # qm comment + 2 : # colon comment + 3 + print a +} + +# test beginning of line block comments (com2.awk) +BEGIN { + print "hi" # comment 1 +# comment 2 + print "there" + + if (foo) { + print "hello" # comment 3 +# comment 4 + print "world" + } +} diff --git a/test/profile11.ok b/test/profile11.ok new file mode 100644 index 00000000..77f4dd7f --- /dev/null +++ b/test/profile11.ok @@ -0,0 +1,371 @@ +@load "filefuncs" # get file functions + +# comments/for.awk +BEGIN { + for (i = 1; i <= 10; i++) { + print i + } + for (i = 1; i <= 10; i++) { # comment 0 + print i + } + for (i = 1; # comment 1a + i <= 10; i++) { + print i + } + for (i = 1; i <= 10; # comment 2a + i++) { + print i + } + for (i = 1; # comment 1b + i <= 10; # comment 2b + i++) { + print i + } + for (i = 1; # comment 1c + i <= 10; # comment 2c + i++) { # comment 3c + print i + } +} + +# comments/for0.awk +BEGIN { + for (iggy in foo) { + # comment 5 + + # comment 6 + } +} + +# comments/for1.awk +BEGIN { + for (iggy in foo) { + # comment 1 + + # comment 2 + print iggy + } + for (iggy in foo) { + # comment 3 + + # comment 4 + print iggy + } + for (iggy in foo) { + # comment 5 + + # comment 6 + } +} + +# comments/for2.awk +BEGIN { + for (;;) { + print i + } + for (;;) { # comment 0 + print i + } + for (; # comment 1a + ; ) { + print i + } + for (; ; # comment 2a + ) { + print i + } + for (; # comment 1b + ; # comment 2b + ) { + print i + } + for (; # comment 1c + ; # comment 2c + ) { # comment 3c + print i + } +} + +# comments/for_del.awk +BEGIN { + for (iggy in foo) { + delete foo[iggy] + } +} + +# comments/do.awk +BEGIN { + do { # DO comment + # LBRACE comment + # block comment + print 42 + } while (0) # WHILE comment + # rbrace comment +} + +# comments/do2.awk +BEGIN { + do { # DO comment + # LBRACE comment + # block comment + print 42 + } while (0) # rbrace comment +} + +# comments2/do.awk +BEGIN { + do { # do comment + # lbrace comment + # block comment + print 42 + } while (1) # while comment + # rbace EOL comment + # rbrace block comment +} + +# comments2/if.awk +BEGIN { + if (a) { + # IF comment + print "foo" # print comment + } + if (a) { # lbrace comment + # IF comment 2 + print "bar" + } else { + # ELSE comment + print "baz" + } +} + +# comments/if0.awk +BEGIN { + if (a) { + # nothing + } else { + print "b" + } +} + +# comments/switch.awk +BEGIN { + a = 5 + switch (a) { + # switch EOL comment + + # switch block comment + + # lbrace EOL comment + + # lbrace block comment + case 5: # comment after case + print "five!" + break + # block comment after case + default: # comment after default + print "default" # print comment + break + } + # rbrace EOL comment + # rbrace block comment +} + +# comments2/switch.awk +BEGIN { + a = 5 + switch (a) { + # switch EOL comment + + # switch block comment + + # lbrace EOL comment + + # lbrace block comment + case 5: + print "five!" + break + # block comment after case + } + # rbrace EOL comment + # rbrace block comment +} + +# comments2/switch0.awk +BEGIN { + a = 5 + switch (a) { + case 5: # case comment + print "five!" + break + default: # default comment + print "default" + break + } +} + +# comments2/switch1.awk +BEGIN { + a = 5 + switch (a) { + case 5: + # case comment + print "five!" + break + default: # default comment + print "default" + break + } +} + +# comments2/while.awk +BEGIN { + while (1) { + # while comment + # lbrace comment + # block comment + print 42 + } +} + +# comments2/while2.awk +BEGIN { + while (1) { + # while comment + # lbrace comment + # block comment + } +} + +BEGIN { + callme(1, # 1 comment + 2, # 2 comment + 3) +} + +# comments/load.awk +BEGIN { + stat("/etc/passwd", data) + for (i in data) { + print i, data[i] + } +} + +# comments/andor.awk +BEGIN { + if (a && # and comment + b || # or comment + c) { + print "foo" + } +} + +# comments/qmcol-qm.awk +BEGIN { + a = 1 ? # qm comment + 2 : 3 + print a +} + +# comments/qmcol-colon.awk +BEGIN { + a = 1 ? 2 : # colon comment + 3 + print a +} + +# comments/qmcolboth.awk +BEGIN { + a = 1 ? # qm comment + 2 : # colon comment + 3 + print a +} + +# test beginning of line block comments (com2.awk) +BEGIN { + print "hi" # comment 1 + # comment 2 + print "there" + if (foo) { + print "hello" # comment 3 + # comment 4 + print "world" + } +} + +# comments/exp.awk +# range comment +# range comment 2 + +# range comment b + +# range comment c +/foo/, /bar/ { + print +} + + +# comments2/f.awk +function bar(p1, p2) +{ + print "foo" +} + +# rbrace eol bar + +# rbrace block bar + +# comments2/function.awk + +# comment + +# comment before braces +function baz(p1, p2) +{ + # lbrace eol + # lbrace block + print "foo" +} + +# rbrace EOL comment funnyhaha + +# rbrace block comment funnyhaha + +# comments/callcoma.awk +function callme(a, b, c) +{ + printf "a = %s, b = %s, c = %s\n", # format comment + a, # a2 comment + b, # b2 comment + c +} + +# rbrace eol baz + +# rbrace block baz + +# comments/function.awk + +# param comment 1 + +# param comment 2 + +# Comment between header and body +function funny(param1, param2, param3, param4) +{ + # lbrace EOL comment + # lbrace block comment + print "funny" +} + +# rbrace EOL comment funny + +# rbrace block comment funny + +# comments/function2.awk +function funnyhaha(param1, param2, param3, param4) +{ + # lbrace EOL comment + # lbrace block comment + print "funny" +} diff --git a/test/profile5.ok b/test/profile5.ok index c8abf1fb..e15e96a2 100644 --- a/test/profile5.ok +++ b/test/profile5.ok @@ -3,7 +3,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################ BINMODE = "rw" SUBSEP = "\000" _NULARR[""] @@ -24,7 +24,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# _delay_perfmsdelay = 11500 } @@ -36,12 +36,13 @@ BEGIN { BEGIN { } -BEGIN { ########################################################################### +########################################################################### +BEGIN { _addlib("_EXTFN") } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# delete _XCHR delete _ASC delete _CHR @@ -101,7 +102,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# _SYS_STDCON = "CON" _CON_WIDTH = match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80 } @@ -111,7 +112,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# if (_SYS_STDOUT == "") { _SYS_STDOUT = "/dev/stdout" } @@ -133,7 +134,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# _tInBy = "\212._tInBy" _tgenuid_init() _UIDS[""] @@ -165,7 +166,7 @@ BEGIN { } #___________________________________________________________________________________ -BEGIN { +BEGIN { ############################################################################# if (_gawk_scriptlevel < 1) { _ERRLOG_TF = 1 _ERRLOG_VF = 1 @@ -186,7 +187,8 @@ BEGIN { _shortcut_init() } -BEGIN { ######################################################### +######################################################### +BEGIN { _addlib("_eXTFN") } @@ -195,7 +197,8 @@ BEGIN { _extfn_init() } -BEGIN { ############################################################ +############################################################ +BEGIN { _addlib("_sHARE") } @@ -282,7 +285,7 @@ BEGIN { #BootDevice BuildNumber BuildType Caption CodeSet CountryCode CreationClassName CSCreationClassName CSDVersion CSName CurrentTimeZone DataExecutionPrevention_32BitApplications DataExecutionPrevention_Available DataExecutionPrevention_Drivers DataExecutionPrevention_SupportPolicy Debug Description Distributed EncryptionLevel ForegroundApplicationBoost FreePhysicalMemory FreeSpaceInPagingFiles FreeVirtualMemory InstallDate LargeSystemCache LastBootUpTime LocalDateTime Locale Manufacturer MaxNumberOfProcesses MaxProcessMemorySize MUILanguages Name NumberOfLicensedUsers NumberOfProcesses NumberOfUsers OperatingSystemSKU Organization OSArchitecture OSLanguage OSProductSuite OSType OtherTypeDescription PAEEnabled PlusProductID PlusVersionNumber Primary ProductType RegisteredUser SerialNumber ServicePackMajorVersion ServicePackMinorVersion SizeStoredInPagingFiles Status SuiteMask SystemDevice SystemDirectory SystemDrive TotalSwapSpaceSize TotalVirtualMemorySize TotalVisibleMemorySize Version WindowsDirectory #\Device\HarddiskVolume1 7601 Multiprocessor Free Microsoft Windows Server 2008 R2 Enterprise 1252 1 Win32_OperatingSystem Win32_ComputerSystem Service Pack 1 CPU 180 TRUE TRUE TRUE 3 FALSE FALSE 256 0 6925316 33518716 41134632 20110502192745.000000+180 20130426120425.497469+180 20130510134606.932000+180 0409 Microsoft Corporation -1 8589934464 {"en-US"} Microsoft Windows Server 2008 R2 Enterprise |C:\Windows|\Device\Harddisk0\Partition2 0 116 2 10 64-bit 1033 274 18 TRUE 3 Windows User 55041-507-2389175-84833 1 0 33554432 OK 274 \Device\HarddiskVolume2 C:\Windows\system32 C: 50311020 16758448 6.1.7601 C:\Windows -BEGIN { +BEGIN { ############################################################################ a = ENVIRON["EGAWK_CMDLINE"] gsub(/^[ \t]*/, "", a) a = _lib_CMDLN(a) @@ -302,13 +305,13 @@ BEGIN { } #_____________________________________________________________________________ -END { +END { ######################################################################## _EXIT() } #_______________________________________________________________________ ######################################################################## -END { +END { ############################################################################### if (_gawk_scriptlevel < 1) { close(_errlog_file) p = _Zimport(_rdfile(_errlog_file), _N()) @@ -329,7 +332,7 @@ END { #_____________________________________________________________________________ # _rQBRO(ptr) - Returns brothers total quantity. [TESTED] # If !ptr then returns "". -END { +END { ############################################################################### if (_gawk_scriptlevel < 1) { if (! _fileio_notdeltmpflag) { _FILEIO_TMPATHS[_FILEIO_TMPRD] @@ -629,7 +632,7 @@ END { # var _gawk_scriptlevel #___________________________________________________________________________________ #################################################################################### -END { +END { ############################################################################### if (_constatstrln > 0) { _constat() } @@ -757,8 +760,8 @@ function _DS(c, t, P, a, A) { ###################################################### switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - #___________________________________________________________ return t #_____________________________________________________ case "_lib_APPLY": @@ -922,14 +925,15 @@ function _FILEIO(c, t, P, A) } ############################################################ + +#_____________________________________________________________________________ function _FILEVER(c, t, P, a, A) { - #_____________________________________________________________________________ + ################################################# switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - ################################################# return t - #___________________________________________________________ #_____________________________________________________ case "_lib_APPLY": return @@ -1494,11 +1498,13 @@ function _addlist(A, v) } ############################################ + +#_______________________________________________________________________ function _bearray(A) { - #_______________________________________________________________________ + #################################################### if (isarray(A) || (A == 0 && A == "")) { - return 1 #################################################### + return 1 } } @@ -2534,10 +2540,12 @@ function _ffaccr(A, t, p, P) } ################## + +#_______________________________________________________________________ function _fframe(A, t, p) { - #_______________________________________________________________________ - return _fframe_i0(A, t, p, A[""]) ################################################# + ################################################# + return _fframe_i0(A, t, p, A[""]) } #___________________________________________________________ @@ -2874,14 +2882,15 @@ function _formatstrd_init() } #__________________________________________________________________________________ + +#################################################################################### + + + + +#___________________________________________________________________________________ function _formatstrs(t) { - #################################################################################### - - - - - #___________________________________________________________________________________ _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB) _formatstrs0 = "" for (t = 1; t < _formatstrq0; t++) { @@ -3026,8 +3035,8 @@ function _getchrln(s, w) ################################################# if (s == "") { return + #if ( w!=w+0 || w<0 ) w=_CON_WIDTH } - #if ( w!=w+0 || w<0 ) w=_CON_WIDTH if (length(s) < w) { if (s in _GETCHRLN) { if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) { @@ -3453,9 +3462,10 @@ function _insframe(A, f) } ######################## + +#_________________________________________________________________ function _inspass(A, f) { - #_________________________________________________________________ A[f] = A[""] A[""] = f } @@ -3782,9 +3792,10 @@ function _newdir(f) } ############################## + +#_______________________________________________________________________ function _nop(p0, p1, p2, p3) { - #_______________________________________________________________________ } #_____________________________________________________ @@ -4202,14 +4213,15 @@ function _qstrq(t) } ################################################################ + +#_____________________________________________________________________________ function _rEG(c, t, P, a, A) { - #_____________________________________________________________________________ + ##################################################### switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - ##################################################### return t - #___________________________________________________________ #_____________________________________________________ case "_lib_APPLY": return @@ -4255,10 +4267,12 @@ function _rFCHLD(p) } ######################## p="", !v + +#_______________________________________________________________________ function _rLBRO(p) { - #_______________________________________________________________________ - if (p) { ###################################################### + ###################################################### + if (p) { if (p in _tPARENT) { return _tLCHLD[_tPARENT[p]] } @@ -4271,10 +4285,12 @@ function _rLBRO(p) } ######################## p="" + +#_______________________________________________________________________ function _rLCHLD(p) { - #_______________________________________________________________________ - if ((p) && (p in _tLCHLD)) { ##################################################### + ##################################################### + if ((p) && (p in _tLCHLD)) { return _tLCHLD[p] } return "" @@ -4288,40 +4304,48 @@ function _rLINK(p) } ######################## p="" + +#_______________________________________________________________________ function _rNEXT(p) { - #_______________________________________________________________________ - if ((p) && (p in _tNEXT)) { ###################################################### + ###################################################### + if ((p) && (p in _tNEXT)) { return _tNEXT[p] } return "" } ######################## p="" + +#_______________________________________________________________________ function _rPARENT(p) { - #_______________________________________________________________________ - if ((p) && (p in _tPARENT)) { #################################################### + #################################################### + if ((p) && (p in _tPARENT)) { return _tPARENT[p] } return "" } ######################## p="" + +#_______________________________________________________________________ function _rPREV(p) { - #_______________________________________________________________________ - if ((p) && (p in _tPREV)) { ###################################################### + ###################################################### + if ((p) && (p in _tPREV)) { return _tPREV[p] } return "" } ######################## p="" + +#_______________________________________________________________________ function _rQBRO(p, c, p1) { - #_______________________________________________________________________ - if (p) { ################################################ + ################################################ + if (p) { if (p in _tPARENT) { return _tQCHLD[_tPARENT[p]] } @@ -4341,10 +4365,12 @@ function _rQBRO(p, c, p1) } ######################## p="" + +#_______________________________________________________________________ function _rQCHLD(p) { - #_______________________________________________________________________ - if ((p) && (p in _tQCHLD)) { ##################################################### + ##################################################### + if ((p) && (p in _tQCHLD)) { return _tQCHLD[p] } return "" @@ -4909,14 +4935,15 @@ function _rxpfn(R, t, p, i, f, A) } ############################################################## + +#_____________________________________________________________________________ function _sHARE(c, t, P, a, A) { - #_____________________________________________________________________________ + ################################################### switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - ################################################### return t - #___________________________________________________________ #_____________________________________________________ case "_lib_APPLY": return @@ -4936,14 +4963,15 @@ function _sHARE(c, t, P, a, A) } ################################################################ + +#_____________________________________________________________________________ function _sYS(c, t, P, a, A) { - #_____________________________________________________________________________ + ##################################################### switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - ##################################################### return t - #___________________________________________________________ #_____________________________________________________ case "_lib_APPLY": return @@ -5004,9 +5032,9 @@ function _setmpath(p, a) if ((p) && (a = _filerd(p))) { if (_FILEIO_TMPRD) { _FILEIO_TMPATHS[_FILEIO_TMPRD] + #if ( _filexist(a) ) _del(a) + #_cmd("rd " a " /S /Q 2>NUL"); _cmd("del " a " /Q 2>NUL") } - #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) : "")) @@ -5051,27 +5079,26 @@ 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 (_isnotfileptr(S)) { # array* - define shortcut-specific elements in array by default values - _addarrmask(D, _[S], _SHORTCUTWSTRUC) + } else if (S == 0 && S == "") { + _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) # array,array2* - copy from array2 to array shorcut-specific elements + } else if (_isnotfileptr(S)) { + _addarrmask(D, _[S], _SHORTCUTWSTRUC) # array* - define shortcut-specific elements in array by default values } else if (_rd_shortcut(D, S)) { - return # array,ptr* - copy from array _[ptr] to array shorcut-specific elements - } + return + } # array,ptr* - copy from array _[ptr] to array shorcut-specific elements } else if (D == 0 && D == "") { - return _NOP # array,filepath* - define in array shortcut-specific elements by reading its from shortcut file filepath(load shortcut) - # -* - no action(return -) + return _NOP # -* - no action(return -) } else if (_isnotfileptr(D)) { 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 (_isnotfileptr(S)) { # ptr* - define shortcut-specifc elements in array _[ptr] by default values - _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) + _addarrmask(_[D], S, _SHORTCUTWSTRUC) # array,filepath* - define in array shortcut-specific elements by reading its from shortcut file filepath(load shortcut) + } else if (S == 0 && S == "") { + _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) # ptr,array* - copy from array to array _[ptr] shorcut-specific elements + } else if (_isnotfileptr(S)) { + _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) # ptr* - define shortcut-specifc elements in array _[ptr] by default values } else 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) + return + } # ptr,ptr2* - copy from array _[ptr2] to array _[ptr] shorcut-specific elements + } else { if (isarray(S) && _wr_shortcut(D, S)) { return # filepath,array* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array(save shortcut) } else if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) { @@ -5080,7 +5107,8 @@ function _shortcut(D, S) return # filepath,ptr* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array _[ptr](save shortcut) } else if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) { return - } } # filepath,filepath2* - [over]write shorcut file filepath; shortcut parameters will be defined from shortcut file filepath2(copy shortcut) + } # ptr,filepath* - define in array _[ptr] shortcut-specific elements by reading its from shortcut file filepath(load shortcut) + } # filepath,filepath2* - [over]write shorcut file filepath; shortcut parameters will be defined from shortcut file filepath2(copy shortcut) return 1 } @@ -5433,8 +5461,8 @@ function _sysinfo(D, h) function _tOBJ(c, t, P) { switch (c) { + #___________________________________________________________ case "_lib_CMDLN": - #___________________________________________________________ return t #___________________________________________________________ case "_lib_APPLY": @@ -6291,30 +6319,34 @@ function _th0(p, p1, p2, p3) } ########################################## + +#_________________________________________________________________ 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 } @@ -7234,10 +7266,10 @@ function _wFBRO(p, v, a) } ######################## p=ptr, v=0 return v } - } else { ######################## p=ptr, v="" + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" if (v) { return _texclude(v) ######################## p="", v=ptr - exclude v } @@ -7325,10 +7357,10 @@ function _wFCHLD(p, v, a) } return v } - } else { ######################## p=ptr, v="" > ignore action + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" > ignore action return v } } @@ -7436,10 +7468,10 @@ function _wLBRO(p, v, a) } ######################## p=ptr, v=0 return v } - } else { ######################## p=ptr, v="" + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" if (v) { return _texclude(v) ######################## p="", v=ptr - exclude v } @@ -7527,10 +7559,10 @@ function _wLCHLD(p, v, a) } return v } - } else { ######################## p=ptr, v="" > ignore action + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" > ignore action return v } } @@ -7606,10 +7638,10 @@ function _wNEXT(p, v, a, b) } ######################## p=ptr, v=0 return v } - } else { ######################## p=ptr, v="" + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" if (v) { return _texclude(v) ######################## p="", v=ptr - exclude v } @@ -7688,10 +7720,10 @@ function _wPREV(p, v, a, b) } ######################## p=ptr, v=0 return v } - } else { ######################## p=ptr, v="" + } else { if (p == 0) { return v ######################## p=0 - } + } ######################## p=ptr, v="" if (v) { return _texclude(v) ######################## p="", v=ptr - exclude v } @@ -7712,10 +7744,10 @@ function _wQCHLD(p, v) ############################################# if (p) { if (v) { - } else { ######################## p=ptr, v=ptr + } else { if (v == 0) { if (p in _tFCHLD) { ######################## p=ptr, v=0 > delete all chld - v = _tFCHLD[p] + v = _tFCHLD[p] ######################## p=ptr, v=ptr delete _tFCHLD[p] delete _tLCHLD[p] delete _tQCHLD[p] @@ -7726,9 +7758,9 @@ function _wQCHLD(p, v) } return v } - } else { ######################## p=ptr, v="" > ignore action + } else { if (p == 0) { - return v + return v ######################## p=ptr, v="" > ignore action } ######################## p=0 return v } diff --git a/test/sourcesplit.ok b/test/sourcesplit.ok index 7ed6ff82..c883f51c 100644 --- a/test/sourcesplit.ok +++ b/test/sourcesplit.ok @@ -1 +1,3 @@ -5 +gawk: cmd. line:1: BEGIN { a = 5; +gawk: cmd. line:1: ^ unexpected newline or end of string +EXIT CODE: 1 diff --git a/test/symtab6.ok b/test/symtab6.ok index 7de717a0..23a1633d 100644 --- a/test/symtab6.ok +++ b/test/symtab6.ok @@ -1,28 +1,2 @@ -ARGC: 1 -ARGIND: 0 -ARGV: array, 1 elements -BINMODE: 0 -CONVFMT: "%.6g" -ERRNO: "" -FIELDWIDTHS: "" -FILENAME: "" -FNR: 0 -FPAT: "[^[:space:]]+" -FS: " " -FUNCTAB: array, 41 elements -IGNORECASE: 0 -LINT: 0 -NF: 0 -NR: 0 -OFMT: "%.6g" -OFS: " " -ORS: "\n" -PREC: 53 -RLENGTH: 0 -ROUNDMODE: "N" -RS: "\n" -RSTART: 0 -RT: "" -SUBSEP: "\034" -SYMTAB: array, 29 elements -TEXTDOMAIN: "messages" +gawk: ./symtab6.awk:1: fatal: cannot assign to arbitrary elements of SYMTAB +EXIT CODE: 2 diff --git a/test/symtab7.ok b/test/symtab7.ok index 28328831..37de1a49 100644 --- a/test/symtab7.ok +++ b/test/symtab7.ok @@ -1,2 +1,2 @@ -30 -40 +gawk: symtab7.awk:4: (FILENAME=- FNR=1) fatal: cannot assign to arbitrary elements of SYMTAB +EXIT CODE: 2 diff --git a/test/testext.ok b/test/testext.ok index 897a7336..fbc3c263 100644 --- a/test/testext.ok +++ b/test/testext.ok @@ -86,6 +86,9 @@ message_string = hello, world new_array["hello"] = "world" new_array["answer"] = "42" +test::testval = in namespace test +test::test_function() called. + at_exit2 called (should be first): data = NULL, exit_status = 0 at_exit1 called (should be second): (data is & data_for_1), data value = 0xdeadbeef, exit_status = 0 at_exit0 called (should be third): data = NULL, exit_status = 0 diff --git a/test/unterm.ok b/test/unterm.ok index 760d3703..399f626a 100644 --- a/test/unterm.ok +++ b/test/unterm.ok @@ -1,5 +1,5 @@ gawk: unterm.awk:1: BEGIN{x=".........................................................................................................................................................................................................................................................} gawk: unterm.awk:1: ^ unterminated string -gawk: unterm.awk:1: BEGIN{x=".........................................................................................................................................................................................................................................................} -gawk: unterm.awk:1: ^ syntax error +gawk: unterm.awk:1: (END OF FILE) +gawk: unterm.awk:1: ^ source files / command-line arguments must contain complete functions or rules EXIT CODE: 1 |