diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2014-09-10 08:18:21 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2014-09-10 08:18:21 +0300 |
commit | 6de0102373304c0fdf70a7ddeb17dd1caa3a9b23 (patch) | |
tree | 7a8f3f18180e0b84893a4cccd883c80ffb7d9bc0 | |
parent | d7c8dfd41bd5671ddfa6c81b2ef1779cab06e56b (diff) | |
parent | ca9f23d6c33c4b5cb3786d480948a42988ca99ac (diff) | |
download | egawk-6de0102373304c0fdf70a7ddeb17dd1caa3a9b23.tar.gz egawk-6de0102373304c0fdf70a7ddeb17dd1caa3a9b23.tar.bz2 egawk-6de0102373304c0fdf70a7ddeb17dd1caa3a9b23.zip |
Merge branch 'master' into comment
53 files changed, 11512 insertions, 10554 deletions
@@ -1,3 +1,109 @@ +2014-09-07 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h: Move libsigsegv stuff to ... + * main.c: here. Thanks to Yehezkel Bernat for motivating + the cleanup. + * symbol.c (make_symbol, install, install_symbol): Add const to + first parameter. Adjust decls and fix up uses. + +2014-09-05 Arnold D. Robbins <arnold@skeeve.com> + + Add builtin functions to FUNCTAB for consistency. + + * awk.h (Node_builtin_func): New node type. + (install_builtins): Declare new function. + * awkgram.y [DEBUG_USE]: New flag value for debug functions; they + don't go into FUNCTAB. + (install_builtins): New function. + * eval.c (nodetypes): Add Node_builtin_func. + * interpret.h (r_interpret): Rework indirect calls of built-ins + since they're now in the symbol table. + * main.c (main): Call `install_builtins'. + * symbol.c (install): Adjust for Node_builtin_func. + (load_symbols): Ditto. + +2014-09-04 Arnold D. Robbins <arnold@skeeve.com> + + * profile.c (pprint): Case Op_K_for: Improve printing of + empty for loop header. + + Unrelated: Make indirect function calls work for built-in and + extension functions. + + * awkgram.y (lookup_builtin): New function. + * awk.h (builtin_func_t): New typedef. + (lookup_builtin): Declare it. + * interpret.h (r_interpret): For indirect calls, add code to + find and call builtin functions, and call extension functions. + +2014-09-01 Arnold D. Robbins <arnold@skeeve.com> + + * builtin.c (do_substr): Return "" instead of null string in case + result is passed to length() with --lint. Based on discussions in + comp.lang.awk. + + Unrelated: + + * interpret.h (r_interpret): For indirect function call, separate + error message if lookup returned NULL. Otherwise got a core dump. + Thanks to "Kenny McKormack" for the report in comp.lang.awk. + +2014-08-27 Arnold D. Robbins <arnold@skeeve.com> + + * configure.ac: Add test for strcasecmp. + * regcomp.c: Remove special case code around use of strcasecmp(). + * replace.c: Include missing/strncasecmp.c if either strcasecmp() + or strncasecmp() aren't available. + +2014-08-26 Arnold D. Robbins <arnold@skeeve.com> + + * regcomp.c, regex_internal.c: Sync with GBLIC. Why not. + + Unrelated: + + Remove support for MirBSD. It uglified the code too much + for no discernable gain. + + * configure.ac: Remove check for MirBSD and define of + LIBC_IS_BORKED. + * dfa.c: Remove code depending on LIBC_IS_BORKED. + * main.c: Ditto. + * regcomp.c: Ditto. + * NEWS: Updated. + +2014-08-24 Arnold D. Robbins <arnold@skeeve.com> + + * regex.h: Remove underscores in names of parameters in function + declarations. Tweak names as neeeded. + +2014-08-20 Arnold D. Robbins <arnold@skeeve.com> + + * node.c (parse_escape): Max of 2 digits after \x. + +2014-08-18 Arnold D. Robbins <arnold@skeeve.com> + + * symbol.c: General formatting cleanup. + +2014-08-15 Arnold D. Robbins <arnold@skeeve.com> + + * main.c (usage): Adjust whitespace for -L and add "invalid" + as a possible value for it. Report from Robert P. J. Day + <rpjday@crashcourse.ca>. + +2014-08-14 Arnold D. Robbins <arnold@skeeve.com> + + * Makefile.am (SUBDIRS): Put awklib after doc so that examples + get extracted when the doc changes. + +2014-08-13 Arnold D. Robbins <arnold@skeeve.com> + + * builtin.c (do_sub): Move initial allocation of the replacement + string down towards code to do the replacement, with a (we hope) + better guesstimate of how much to initially allocate. The idea + is to avoid unnecessary realloc() calls by making a better guess + at how much to allocate. This came up in an email discussion + with Tom Dickey about mawk's gsub(). + 2014-08-12 Juergen Kahrs <jkahrs@users.sourceforge.net> * cmake/configure.cmake: diff --git a/Makefile.am b/Makefile.am index 9a5e1618..3d1c8837 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,10 +61,12 @@ EXTRA_DIST = \ # The order to do things in. # Build explicitly in "." in order to build gawk first, so # that `make check' without a prior `make' works. +# Build in awklib after in doc, since we want to extract +# sample files if doc/gawk.texi changed. SUBDIRS = \ . \ - awklib \ doc \ + awklib \ po \ extension \ test diff --git a/Makefile.in b/Makefile.in index c44d10b5..5c2a7f11 100644 --- a/Makefile.in +++ b/Makefile.in @@ -467,10 +467,12 @@ EXTRA_DIST = \ # The order to do things in. # Build explicitly in "." in order to build gawk first, so # that `make check' without a prior `make' works. +# Build in awklib after in doc, since we want to extract +# sample files if doc/gawk.texi changed. SUBDIRS = \ . \ - awklib \ doc \ + awklib \ po \ extension \ test @@ -29,6 +29,11 @@ Changes from 4.1.x to 4.2.0 system for those who may want it; gawk is not going to switch off use of the autotools anytime soon, if ever. +7. Gawk now processes a maximum of two hexadecimal digits in \x + escape sequences inside strings. + +8. MirBSD is no longer supported. + Changes from 4.1.1 to 4.1.2 --------------------------- @@ -45,6 +50,9 @@ Changes from 4.1.1 to 4.1.2 4. A number of bugs have been fixed in the MPFR code. +5. Indirect function calls now work for both built-in and + extension functions. + XX. A number of bugs have been fixed. See the ChangeLog. Changes from 4.1.0 to 4.1.1 @@ -1,4 +1,4 @@ -Wed Jun 25 22:28:05 IDT 2014 +Sun Aug 24 20:00:53 IDT 2014 ============================ There were too many files tracking different thoughts and ideas for @@ -33,8 +33,6 @@ Minor Cleanups and Code Improvements Look at function order within files. - regex.h - remove underscores in param names - Consider removing use of and/or need for the protos.h file. Recheck if gnulib regex can be dropped in @@ -193,15 +193,6 @@ extern void *memset_ulong(void *dest, int val, unsigned long l); #define memset memset_ulong #endif -#ifdef HAVE_LIBSIGSEGV -#include <sigsegv.h> -#else -typedef void *stackoverflow_context_t; -#define sigsegv_install_handler(catchsegv) signal(SIGSEGV, catchsig) -/* define as 0 rather than empty so that (void) cast on it works */ -#define stackoverflow_install_handler(catchstackoverflow, extra_stack, STACK_SIZE) 0 -#endif - #if defined(__EMX__) || defined(__MINGW32__) #include "nonposix.h" #endif /* defined(__EMX__) || defined(__MINGW32__) */ @@ -297,6 +288,7 @@ typedef enum nodevals { Node_func, /* lnode is param. list, rnode is body */ Node_ext_func, /* extension function, code_ptr is builtin code */ Node_old_ext_func, /* extension function, code_ptr is builtin code */ + Node_builtin_func, /* built-in function, main use is for FUNCTAB */ Node_array_ref, /* array passed by ref as parameter */ Node_array_tree, /* Hashed array tree (HAT) */ @@ -1379,6 +1371,9 @@ extern void register_deferred_variable(const char *name, NODE *(*load_func)(void extern int files_are_same(char *path, SRCFILE *src); extern void valinfo(NODE *n, Func_print print_func, FILE *fp); extern void negate_num(NODE *n); +typedef NODE *(*builtin_func_t)(int); /* function that implements a built-in */ +extern builtin_func_t lookup_builtin(const char *name); +extern void install_builtins(void); /* builtin.c */ extern double double_to_int(double d); extern NODE *do_exp(int nargs); @@ -1642,7 +1637,7 @@ extern void load_symbols(); extern void init_symbol_table(); extern NODE *symbol_table; extern NODE *func_table; -extern NODE *install_symbol(char *name, NODETYPE type); +extern NODE *install_symbol(const char *name, NODETYPE type); extern NODE *remove_symbol(NODE *r); extern void destroy_symbol(NODE *r); extern void release_symbols(NODE *symlist, int keep_globals); @@ -4409,6 +4409,7 @@ struct token { # define GAWKX 0x0400 /* gawk extension */ # define BREAK 0x0800 /* break allowed inside */ # define CONTINUE 0x1000 /* continue allowed inside */ +# define DEBUG_USE 0x2000 /* for use by developers */ NODE *(*ptr)(int); /* function that implements this keyword */ NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ @@ -4447,7 +4448,7 @@ static const struct token tokentab[] = { {"END", Op_rule, LEX_END, 0, 0, 0}, {"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, #ifdef ARRAYDEBUG -{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, #endif {"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)}, {"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0}, @@ -4507,7 +4508,7 @@ static const struct token tokentab[] = { {"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)}, {"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)}, #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ -{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme, 0}, +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0}, #endif {"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0}, {"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)}, @@ -8423,3 +8424,35 @@ one_line_close(int fd) } +/* lookup_builtin --- find a builtin function or return NULL */ + +builtin_func_t +lookup_builtin(const char *name) +{ + int mid = check_special(name); + + if (mid == -1 || tokentab[mid].class != LEX_BUILTIN) + return NULL; +#ifdef HAVE_MPFR + if (do_mpfr) + return tokentab[mid].ptr2; +#endif + + return tokentab[mid].ptr; +} + +/* install_builtins --- add built-in functions to FUNCTAB */ + +void +install_builtins(void) +{ + int i, j; + + j = sizeof(tokentab) / sizeof(tokentab[0]); + for (i = 0; i < j; i++) { + if ( tokentab[i].class == LEX_BUILTIN + && (tokentab[i].flags & DEBUG_USE) == 0) { + (void) install_symbol(tokentab[i].operator, Node_builtin_func); + } + } +} @@ -1862,6 +1862,7 @@ struct token { # define GAWKX 0x0400 /* gawk extension */ # define BREAK 0x0800 /* break allowed inside */ # define CONTINUE 0x1000 /* continue allowed inside */ +# define DEBUG_USE 0x2000 /* for use by developers */ NODE *(*ptr)(int); /* function that implements this keyword */ NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ @@ -1900,7 +1901,7 @@ static const struct token tokentab[] = { {"END", Op_rule, LEX_END, 0, 0, 0}, {"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, #ifdef ARRAYDEBUG -{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, #endif {"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)}, {"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0}, @@ -1960,7 +1961,7 @@ static const struct token tokentab[] = { {"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)}, {"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)}, #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ -{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme, 0}, +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0}, #endif {"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0}, {"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)}, @@ -5876,3 +5877,35 @@ one_line_close(int fd) } +/* lookup_builtin --- find a builtin function or return NULL */ + +builtin_func_t +lookup_builtin(const char *name) +{ + int mid = check_special(name); + + if (mid == -1 || tokentab[mid].class != LEX_BUILTIN) + return NULL; +#ifdef HAVE_MPFR + if (do_mpfr) + return tokentab[mid].ptr2; +#endif + + return tokentab[mid].ptr; +} + +/* install_builtins --- add built-in functions to FUNCTAB */ + +void +install_builtins(void) +{ + int i, j; + + j = sizeof(tokentab) / sizeof(tokentab[0]); + for (i = 0; i < j; i++) { + if ( tokentab[i].class == LEX_BUILTIN + && (tokentab[i].flags & DEBUG_USE) == 0) { + (void) install_symbol(tokentab[i].operator, Node_builtin_func); + } + } +} diff --git a/awklib/eg/lib/getopt.awk b/awklib/eg/lib/getopt.awk index db957ceb..6b1f4c50 100644 --- a/awklib/eg/lib/getopt.awk +++ b/awklib/eg/lib/getopt.awk @@ -38,8 +38,7 @@ function getopt(argc, argv, options, thisopt, i) i = index(options, thisopt) if (i == 0) { if (Opterr) - printf("%c -- invalid option\n", - thisopt) > "/dev/stderr" + printf("%c -- invalid option\n", thisopt) > "/dev/stderr" if (_opti >= length(argv[Optind])) { Optind++ _opti = 0 diff --git a/awklib/eg/lib/groupawk.in b/awklib/eg/lib/groupawk.in index 0917b923..9382bce8 100644 --- a/awklib/eg/lib/groupawk.in +++ b/awklib/eg/lib/groupawk.in @@ -5,8 +5,7 @@ # Revised October 2000 # Revised December 2010 -BEGIN \ -{ +BEGIN { # Change to suit your system _gr_awklib = "/usr/local/libexec/awk/" } diff --git a/awklib/eg/lib/strtonum.awk b/awklib/eg/lib/strtonum.awk index 9342e789..5e20626b 100644 --- a/awklib/eg/lib/strtonum.awk +++ b/awklib/eg/lib/strtonum.awk @@ -13,8 +13,9 @@ function mystrtonum(str, ret, n, i, k, c) ret = 0 for (i = 1; i <= n; i++) { c = substr(str, i, 1) - if ((k = index("01234567", c)) > 0) - k-- # adjust for 1-basing in awk + # index() returns 0 if c not in string, + # includes c == "0" + k = index("1234567", c) ret = ret * 8 + k } @@ -26,6 +27,8 @@ function mystrtonum(str, ret, n, i, k, c) for (i = 1; i <= n; i++) { c = substr(str, i, 1) c = tolower(c) + # index() returns 0 if c not in string, + # includes c == "0" k = index("123456789abcdef", c) ret = ret * 16 + k diff --git a/awklib/eg/prog/alarm.awk b/awklib/eg/prog/alarm.awk index 63cf64a4..59630ea8 100644 --- a/awklib/eg/prog/alarm.awk +++ b/awklib/eg/prog/alarm.awk @@ -8,8 +8,7 @@ # usage: alarm time [ "message" [ count [ delay ] ] ] -BEGIN \ -{ +BEGIN { # Initial argument sanity checking usage1 = "usage: alarm time ['message' [count [delay]]]" usage2 = sprintf("\t(%s) time ::= hh:mm", ARGV[1]) diff --git a/awklib/eg/prog/cut.awk b/awklib/eg/prog/cut.awk index 04d9bc11..56e35e71 100644 --- a/awklib/eg/prog/cut.awk +++ b/awklib/eg/prog/cut.awk @@ -20,8 +20,7 @@ function usage( e1, e2) print e2 > "/dev/stderr" exit 1 } -BEGIN \ -{ +BEGIN { FS = "\t" # default OFS = FS while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) { diff --git a/awklib/eg/prog/egrep.awk b/awklib/eg/prog/egrep.awk index 86b3cfda..094bdea5 100644 --- a/awklib/eg/prog/egrep.awk +++ b/awklib/eg/prog/egrep.awk @@ -88,8 +88,7 @@ function endfile(file) print } } -END \ -{ +END { exit (total == 0) } function usage( e) diff --git a/awklib/eg/prog/id.awk b/awklib/eg/prog/id.awk index cf744447..992fa57c 100644 --- a/awklib/eg/prog/id.awk +++ b/awklib/eg/prog/id.awk @@ -11,8 +11,7 @@ # uid=12(foo) euid=34(bar) gid=3(baz) \ # egid=5(blat) groups=9(nine),2(two),1(one) -BEGIN \ -{ +BEGIN { uid = PROCINFO["uid"] euid = PROCINFO["euid"] gid = PROCINFO["gid"] diff --git a/awklib/eg/prog/labels.awk b/awklib/eg/prog/labels.awk index abf53c3b..3195809b 100644 --- a/awklib/eg/prog/labels.awk +++ b/awklib/eg/prog/labels.awk @@ -48,7 +48,6 @@ function printpage( i, j) Count++ } -END \ -{ +END { printpage() } diff --git a/awklib/eg/prog/tee.awk b/awklib/eg/prog/tee.awk index 639b9f80..fd9985f1 100644 --- a/awklib/eg/prog/tee.awk +++ b/awklib/eg/prog/tee.awk @@ -7,8 +7,7 @@ # May 1993 # Revised December 1995 -BEGIN \ -{ +BEGIN { for (i = 1; i < ARGC; i++) copy[i] = ARGV[i] @@ -35,8 +34,7 @@ BEGIN \ print > copy[i] print } -END \ -{ +END { for (i in copy) close(copy[i]) } diff --git a/awklib/eg/prog/uniq.awk b/awklib/eg/prog/uniq.awk index 990387ac..2a2cf63e 100644 --- a/awklib/eg/prog/uniq.awk +++ b/awklib/eg/prog/uniq.awk @@ -18,8 +18,7 @@ function usage( e) # -n skip n fields # +n skip n characters, skip fields first -BEGIN \ -{ +BEGIN { count = 1 outputfile = "/dev/stdout" opts = "udc0:1:2:3:4:5:6:7:8:9:" @@ -31,7 +30,7 @@ BEGIN \ else if (c == "c") do_count++ else if (index("0123456789", c) != 0) { - # getopt requires args to options + # getopt() requires args to options # this messes us up for things like -5 if (Optarg ~ /^[[:digit:]]+$/) fcount = (c Optarg) + 0 @@ -1759,7 +1759,14 @@ do_substr(int nargs) else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0)) lintwarn(_("substr: length %g is not >= 0"), d_length); DEREF(t1); - return dupnode(Nnull_string); + /* + * Return explicit null string instead of doing + * dupnode(Nnull_string) so that if the result + * is checked with the combination of length() + * and lint, no error is reported about using + * an uninitialized value. Same thing later, too. + */ + return make_string("", 0); } if (do_lint) { if (double_to_int(d_length) != d_length) @@ -1813,7 +1820,7 @@ do_substr(int nargs) if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0))) lintwarn(_("substr: source string is zero length")); DEREF(t1); - return dupnode(Nnull_string); + return make_string("", 0); } /* get total len of input string, for following checks */ @@ -1830,7 +1837,7 @@ do_substr(int nargs) lintwarn(_("substr: start index %g is past end of string"), d_index); DEREF(t1); - return dupnode(Nnull_string); + return make_string("", 0); } if (length > src_len - indx) { if (do_lint) @@ -2847,16 +2854,11 @@ set_how_many: text = t->stptr; textlen = t->stlen; - buflen = textlen + 2; repl = s->stptr; replend = repl + s->stlen; repllen = replend - repl; - emalloc(buf, char *, buflen + 2, "do_sub"); - buf[buflen] = '\0'; - buf[buflen + 1] = '\0'; - ampersands = 0; /* @@ -2915,6 +2917,13 @@ set_how_many: } lastmatchnonzero = false; + + /* guesstimate how much room to allocate; +2 forces > 0 */ + buflen = textlen + (ampersands + 1) * repllen + 2; + emalloc(buf, char *, buflen + 2, "do_sub"); + buf[buflen] = '\0'; + buf[buflen + 1] = '\0'; + bp = buf; for (current = 1;; current++) { matches++; @@ -195,6 +195,9 @@ /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR @@ -317,9 +320,6 @@ /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL -/* libc is broken for regex handling */ -#undef LIBC_IS_BORKED - /* disable lint checks */ #undef NO_LINT @@ -5999,14 +5999,6 @@ then CFLAGS="$CFLAGS -D_SYSV3" fi -case $host_os in -mirbsd*) - -$as_echo "#define LIBC_IS_BORKED 1" >>confdefs.h - - ;; -esac - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -10007,7 +9999,7 @@ for ac_func in atexit btowc fmod getgrent getgroups grantpt \ isascii iswctype iswlower iswupper mbrlen \ memcmp memcpy memcpy_ulong memmove memset \ memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \ - strerror strftime strncasecmp strcoll strtod strtoul \ + strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ system tmpfile towlower towupper tzset usleep wcrtomb \ wcscoll wctype do : diff --git a/configure.ac b/configure.ac index e7e2d5f6..8b4f188e 100644 --- a/configure.ac +++ b/configure.ac @@ -119,13 +119,6 @@ dnl need -D_SYSV3 for ISC CFLAGS="$CFLAGS -D_SYSV3" fi -dnl check for systems where libc is borked for regex handling -case $host_os in -mirbsd*) - AC_DEFINE([LIBC_IS_BORKED], 1, [libc is broken for regex handling]) - ;; -esac - dnl Set the programming language for checks. Fortunately, dnl this only needs to be set once, since everything is in C. AC_LANG([C]) @@ -275,7 +268,7 @@ AC_CHECK_FUNCS(atexit btowc fmod getgrent getgroups grantpt \ isascii iswctype iswlower iswupper mbrlen \ memcmp memcpy memcpy_ulong memmove memset \ memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \ - strerror strftime strncasecmp strcoll strtod strtoul \ + strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ system tmpfile towlower towupper tzset usleep wcrtomb \ wcscoll wctype) dnl this check is for both mbrtowc and the mbstate_t type, which is good @@ -77,14 +77,6 @@ is_blank (int c) } #endif /* GAWK */ -#ifdef LIBC_IS_BORKED -extern int gawk_mb_cur_max; -#undef MB_CUR_MAX -#define MB_CUR_MAX gawk_mb_cur_max -#undef mbrtowc -#define mbrtowc(a, b, c, d) (-1) -#endif - /* HPUX defines these as macros in sys/param.h. */ #ifdef setbit # undef setbit @@ -828,10 +820,6 @@ using_utf8 (void) wchar_t wc; mbstate_t mbs = { 0 }; utf8 = mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100; -#ifdef LIBC_IS_BORKED - if (gawk_mb_cur_max == 1) - utf8 = 0; -#endif } return utf8; } diff --git a/doc/ChangeLog b/doc/ChangeLog index 82997ac8..ab2b26c7 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,90 @@ +2014-09-08 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Remove text that won't get used. + +2014-09-07 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Minor cleanups. + +2014-09-05 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Document builtin functions in FUNCTAB and in + PROCINFO["identifiers"]. + * gawk.1: Ditto. + + Unrelated: + + * gawktexi.in: More stuff from reviewer comments. + +2014-09-04 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Document that indirect calls now work on built-in + and extension functions. + * gawk.1: Same. + +2014-09-03 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Further fixes from reviews and bug reports. + +2014-09-02 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Corrections to walkthrough in debugger chapter. + Thanks to David Ward <dlward134@gmail.com> for the problem report. + +2014-09-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Add index entry for @ - @load, @include, + and indirect function calls. Thanks to "Kenny McKormack" in + comp.lang.awk. + +2014-08-29 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments, and other + bug fixes, miscellanious improvements. + +2014-08-26 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Use a different mechanism to exclude + exercises. Remove use of LC_ALL in an example; doesn't seem + to be needed anymore. + + Unrelated: + + * gawktexi.in: Document that MirBSD is no longer supported. + +2014-08-25 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Exercises are excluded from print edition. + +2014-08-24 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-23 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-22 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-20 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-16 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-15 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-13 Arnold D. Robbins <arnold@skeeve.com> + + * gawktexi.in: Starting on reviewer comments. + Update acknowledgements. + 2014-08-12 Arnold D. Robbins <arnold@skeeve.com> * gawktexi.in: Cause div.awk to get into the example files. @@ -13,7 +13,7 @@ . if \w'\(rq' .ds rq "\(rq . \} .\} -.TH GAWK 1 "Jul 10 2014" "Free Software Foundation" "Utility Commands" +.TH GAWK 1 "Aug 03 2014" "Free Software Foundation" "Utility Commands" .SH NAME gawk \- pattern scanning and processing language .SH SYNOPSIS @@ -1132,9 +1132,14 @@ For each identifier, the value of the element is one of the following: \fB"array"\fR The identifier is an array. .TP +\fB"builtin"\fR +The identifier is a built-in function. +.TP \fB"extension"\fR The identifier is an extension function loaded via -.BR @load . +.B @load +or +.BR \-l . .TP \fB"scalar"\fR The identifier is a scalar. @@ -3287,7 +3292,7 @@ sign, like so: .RS .ft B .nf -function myfunc() +function myfunc() { print "myfunc called" \&.\|.\|. @@ -3301,6 +3306,8 @@ function myfunc() .fi .ft R .RE +As of version 4.1.2, this works with user-defined functions, +built-in functions, and extension functions. .PP If .B \-\^\-lint diff --git a/doc/gawk.info b/doc/gawk.info index 076a2f34..2b8c0e0b 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -170,10 +170,10 @@ entitled "GNU Free Documentation License". * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between `[...]'. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. * Records:: Controlling how data is split into records. @@ -190,7 +190,7 @@ entitled "GNU Free Documentation License". * Single Character Fields:: Making each character a separate field. * Command Line Field Separator:: Setting `FS' from the - command-line. + command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -216,7 +216,7 @@ entitled "GNU Free Documentation License". `getline'. * Getline Summary:: Summary of `getline' Variants. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -244,7 +244,7 @@ entitled "GNU Free Documentation License". * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. * Values:: Constants, Variables, and Regular Expressions. * Constants:: String, numeric and regexp constants. @@ -255,7 +255,7 @@ entitled "GNU Free Documentation License". * Variables:: Variables give names to values for later use. * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. * Conversion:: The conversion of strings to numbers @@ -431,7 +431,7 @@ entitled "GNU Free Documentation License". information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. * Running Examples:: How to run these examples. * Clones:: Clones of common utilities. * Cut Program:: The `cut' utility. @@ -769,12 +769,10 @@ Preface Several kinds of tasks occur repeatedly when working with text files. You might want to extract certain lines and discard the rest. Or you -may need to make changes wherever certain patterns appear, but leave -the rest of the file alone. Writing single-use programs for these -tasks in languages such as C, C++, or Java is time-consuming and -inconvenient. Such jobs are often easier with `awk'. The `awk' -utility interprets a special-purpose programming language that makes it -easy to handle simple data-reformatting jobs. +may need to make changes wherever certain patterns appear, but leave the +rest of the file alone. Such jobs are often easy with `awk'. The +`awk' utility interprets a special-purpose programming language that +makes it easy to handle simple data-reformatting jobs. The GNU implementation of `awk' is called `gawk'; if you invoke it with the proper options or environment variables (*note Options::), it @@ -818,12 +816,11 @@ such as input/output (I/O) redirection and pipes. different computing environments. This Info file, while describing the `awk' language in general, also describes the particular implementation of `awk' called `gawk' (which stands for "GNU `awk'"). `gawk' runs on -a broad range of Unix systems, ranging from Intel(R)-architecture -PC-based computers up through large-scale systems. `gawk' has also -been ported to Mac OS X, Microsoft Windows (all versions) and OS/2 PCs, -and OpenVMS. (Some other, obsolete systems to which `gawk' was once -ported are no longer supported and the code for those systems has been -removed.) +a broad range of Unix systems, ranging from Intel-architecture PC-based +computers up through large-scale systems. `gawk' has also been ported +to Mac OS X, Microsoft Windows (all versions) and OS/2 PCs, and OpenVMS. +(Some other, obsolete systems to which `gawk' was once ported are no +longer supported and the code for those systems has been removed.) * Menu: @@ -840,7 +837,7 @@ removed.) ---------- Footnotes ---------- - (1) The 2008 POSIX standard is accessable online at + (1) The 2008 POSIX standard is accessible online at `http://www.opengroup.org/onlinepubs/9699919799/'. (2) These commands are available on POSIX-compliant systems, as well @@ -884,7 +881,7 @@ contributed parts of the code as well. In 1988 and 1989, David Trueman, with help from me, thoroughly reworked `gawk' for compatibility with the newer `awk'. Circa 1994, I became the primary maintainer. Current development focuses on bug fixes, performance improvements, -standards compliance, and occasionally, new features. +standards compliance and, occasionally, new features. In May of 1997, Ju"rgen Kahrs felt the need for network access from `awk', and with a little help from me, set about adding features to do @@ -908,23 +905,19 @@ A Rose by Any Other Name The `awk' language has evolved over the years. Full details are provided in *note Language History::. The language described in this -Info file is often referred to as "new `awk'" (`nawk'). +Info file is often referred to as "new `awk'". By analogy, the +original version of `awk' is referred to as "old `awk'." - For some time after new `awk' was introduced, there were systems -with multiple versions of `awk'. Some systems had an `awk' utility -that implemented the original version of the `awk' language and a -`nawk' utility for the new version. Others had an `oawk' version for -the "old `awk'" language and plain `awk' for the new one. Still others -only had one version, which is usually the new one. + Today, on most systems, when you run the `awk' utility, you get some +version of new `awk'.(1) If your system's standard `awk' is the old +one, you will see something like this if you try the test program: - Today, only Solaris systems still use an old `awk' for the default -`awk' utility. (A more modern `awk' lives in `/usr/xpg6/bin' on these -systems.) All other modern systems use some version of new `awk'.(1) + $ awk 1 /dev/null + error--> awk: syntax error near line 1 + error--> awk: bailing out near line 1 - It is likely that you already have some version of new `awk' on your -system, which is what you should use when running your programs. (Of -course, if you're reading this Info file, chances are good that you -have `gawk'!) +In this case, you should find a version of new `awk', or just install +`gawk'! Throughout this Info file, whenever we refer to a language feature that should be available in any complete implementation of POSIX `awk', @@ -933,7 +926,9 @@ specific to the GNU implementation, we use the term `gawk'. ---------- Footnotes ---------- - (1) Many of these systems use `gawk' for their `awk' implementation! + (1) Only Solaris systems still use an old `awk' for the default +`awk' utility. A more modern `awk' lives in `/usr/xpg6/bin' on these +systems. File: gawk.info, Node: This Manual, Next: Conventions, Prev: Names, Up: Preface @@ -1086,7 +1081,7 @@ formatting language. A single Texinfo source file is used to produce both the printed and online versions of the documentation. This minor node briefly documents the typographical conventions used in Texinfo. - Examples you would type at the command-line are preceded by the + Examples you would type at the command line are preceded by the common shell primary and secondary prompts, `$' and `>'. Input that you type is shown `like this'. Output from the command is preceded by the glyph "-|". This typically represents the command's standard @@ -1105,6 +1100,10 @@ key and another key, at the same time. For example, a `Ctrl-d' is typed by first pressing and holding the `CONTROL' key, next pressing the `d' key and finally releasing both keys. + For the sake of brevity, throughout this Info file, we refer to +Brian Kernighan's version of `awk' as "BWK `awk'." (*Note Other +Versions::, for information on his and other versions.) + Dark Corners ------------ @@ -1155,17 +1154,10 @@ released but remains in an early stage of development. Until the GNU operating system is more fully developed, you should consider using GNU/Linux, a freely distributable, Unix-like operating -system for Intel(R), Power Architecture, Sun SPARC, IBM S/390, and other +system for Intel, Power Architecture, Sun SPARC, IBM S/390, and other systems.(2) Many GNU/Linux distributions are available for download from the Internet. - (There are numerous other freely available, Unix-like operating -systems based on the Berkeley Software Distribution, and some of them -use recent versions of `gawk' for their versions of `awk'. NetBSD -(http://www.netbsd.org), FreeBSD (http://www.freebsd.org), and OpenBSD -(http://www.openbsd.org) are three of the most popular ones, but there -are others.) - The Info file itself has gone through a number of previous editions. Paul Rubin wrote the very first draft of `The GAWK Manual'; it was around 40 pages in size. Diane Close and Richard Stallman improved it, @@ -1300,16 +1292,26 @@ be a pleasure working with this team of fine people. Notable code and documentation contributions were made by a number of people. *Note Contributors::, for the full list. - Thanks to Patrice Dumas for the new `makeinfo' program. Thanks to + Thanks to Patrice Dumas for the new `makeinfo' program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. + Robert P.J. Day, Michael Brennan and Brian Kernighan kindly acted as +reviewers for the 2015 edition of this Info file. Their feedback helped +improve the final work. + I would like to thank Brian Kernighan for invaluable assistance during the testing and debugging of `gawk', and for ongoing help and advice in clarifying numerous points about the language. We could not have done nearly as good a job on either `gawk' or its documentation without his help. + Brian is in a class by himself as a programmer and technical author. +I have to thank him (yet again) for his ongoing friendship and the role +model he has been for me for close to 30 years! Having him as a +reviewer is an exciting privilege. It has also been extremely +humbling... + I must thank my wonderful wife, Miriam, for her patience through the many versions of this project, for her proofreading, and for sharing me with the computer. I would like to thank my parents for their love, @@ -1453,15 +1455,23 @@ end-of-file character may be different. For example, on OS/2, it is As an example, the following program prints a friendly piece of advice (from Douglas Adams's `The Hitchhiker's Guide to the Galaxy'), to keep you from worrying about the complexities of computer -programming(1) (`BEGIN' is a feature we haven't discussed yet): +programming: - $ awk "BEGIN { print \"Don't Panic!\" }" + $ awk "BEGIN { print "Don\47t Panic!" }" -| Don't Panic! - This program does not read any input. The `\' before each of the -inner double quotes is necessary because of the shell's quoting -rules--in particular because it mixes both single quotes and double -quotes.(2) + `awk' executes statements associated with `BEGIN' before reading any +input. If there are no other statements in your program, as is the +case here, `awk' just stops, instead of trying to read input it doesn't +know how to process. The `\47' is a magic way of getting a single +quote into the program, without having to engage in ugly shell quoting +tricks. + + NOTE: As a side note, if you use Bash as your shell, you should + execute the command `set +H' before running this program + interactively, to disable the C shell-style command history, which + treats `!' as a special character. We recommend putting this + command into your personal startup file. This next simple `awk' program emulates the `cat' utility; it copies whatever you type on the keyboard to its standard output (why this @@ -1478,17 +1488,6 @@ works is explained shortly). -| What, me worry? Ctrl-d - ---------- Footnotes ---------- - - (1) If you use Bash as your shell, you should execute the command -`set +H' before running this program interactively, to disable the C -shell-style command history, which treats `!' as a special character. -We recommend putting this command into your personal startup file. - - (2) Although we generally recommend the use of single quotes around -the program text, double quotes are needed here in order to put the -single quote into the message. - File: gawk.info, Node: Long, Next: Executable Scripts, Prev: Read Terminal, Up: Running gawk @@ -1502,8 +1501,8 @@ tell `awk' to use that file for its program, you type: awk -f SOURCE-FILE INPUT-FILE1 INPUT-FILE2 ... The `-f' instructs the `awk' utility to get the `awk' program from -the file SOURCE-FILE. Any file name can be used for SOURCE-FILE. For -example, you could put the program: +the file SOURCE-FILE (*note Options::). Any file name can be used for +SOURCE-FILE. For example, you could put the program: BEGIN { print "Don't Panic!" } @@ -1543,8 +1542,8 @@ like this: BEGIN { print "Don't Panic!" } After making this file executable (with the `chmod' utility), simply -type `advice' at the shell and the system arranges to run `awk'(2) as -if you had typed `awk -f advice': +type `advice' at the shell and the system arranges to run `awk' as if +you had typed `awk -f advice': $ chmod +x advice $ advice @@ -1558,7 +1557,24 @@ at the shell.) program that users can invoke without their having to know that the program is written in `awk'. - Portability Issues with `#!' + Understanding `#!' + + `awk' is an "interpreted" language. This means that the `awk' +utility reads your program and then processes your data according to +the instructions in your program. (This is different from a "compiled" +language such as C, where your program is first compiled into machine +code that is executed directly by your system's hardware.) The `awk' +utility is thus termed an "interpreter". Many modern languages are +interperted. + + The line beginning with `#!' lists the full file name of an +interpreter to run and a single optional initial command-line argument +to pass to that interpreter. The operating system then runs the +interpreter with the given argument and the full argument list of the +executed program. The first argument in the list is the full file name +of the `awk' program. The rest of the argument list contains either +options to `awk', or data files, or both. Note that on many systems +`awk' may be found in `/usr/bin' instead of in `/bin'. Caveat Emptor. Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -1580,15 +1596,6 @@ the name of your script (`advice'). (d.c.) Don't rely on the value of (1) The `#!' mechanism works on GNU/Linux systems, BSD-based systems and commercial Unix systems. - (2) The line beginning with `#!' lists the full file name of an -interpreter to run and an optional initial command-line argument to -pass to that interpreter. The operating system then runs the -interpreter with the given argument and the full argument list of the -executed program. The first argument in the list is the full file name -of the `awk' program. The rest of the argument list contains either -options to `awk', or data files, or both. Note that on many systems -`awk' may be found in `/usr/bin' instead of in `/bin'. Caveat Emptor. - File: gawk.info, Node: Comments, Next: Quoting, Prev: Executable Scripts, Up: Running gawk @@ -1716,9 +1723,9 @@ the quoting rules. Note that the single quote is not special within double quotes. * Null strings are removed when they occur as part of a non-null - command-line argument, while explicit non-null objects are kept. - For example, to specify that the field separator `FS' should be - set to the null string, use: + command-line argument, while explicit null objects are kept. For + example, to specify that the field separator `FS' should be set to + the null string, use: awk -F "" 'PROGRAM' FILES # correct @@ -1811,10 +1818,10 @@ one "record". In the data file `mail-list', each record contains the name of a person, his/her phone number, his/her email-address, and a code for -their relationship with the author of the list. An `A' in the last -column means that the person is an acquaintance. An `F' in the last -column means that the person is a friend. An `R' means that the person -is a relative: +their relationship with the author of the list. The columns are +aligned using spaces. An `A' in the last column means that the person +is an acquaintance. An `F' in the last column means that the person is +a friend. An `R' means that the person is a relative: Amelia 555-5553 amelia.zodiacusque@gmail.com F Anthony 555-3412 anthony.asserturo@hotmail.com A @@ -1833,7 +1840,8 @@ shipments during the year. Each record contains the month, the number of green crates shipped, the number of red boxes shipped, the number of orange bags shipped, and the number of blue packages shipped, respectively. There are 16 entries, covering the 12 months of last year -and the first four months of the current year. +and the first four months of the current year. An empty line separates +the data for the two years. Jan 13 25 15 115 Feb 15 32 24 226 @@ -1913,11 +1921,6 @@ often more than one way to do things in `awk'. At some point, you may want to look back at these examples and see if you can come up with different ways to do the same things shown here: - * Print the length of the longest input line: - - awk '{ if (length($0) > max) max = length($0) } - END { print max }' data - * Print every line that is longer than 80 characters: awk 'length($0) > 80' data @@ -1925,14 +1928,23 @@ different ways to do the same things shown here: The sole rule has a relational expression as its pattern and it has no action--so it uses the default action, printing the record. + * Print the length of the longest input line: + + awk '{ if (length($0) > max) max = length($0) } + END { print max }' data + + The code associated with `END' executes after all input has been + read; it's the other side of the coin to `BEGIN'. + * Print the length of the longest line in `data': - expand data | awk '{ if (x < length()) x = length() } + expand data | awk '{ if (x < length($0)) x = length($0) } END { print "maximum line length is " x }' - The input is processed by the `expand' utility to change TABs into - spaces, so the widths compared are actually the right-margin - columns. + This example differs slightly from the previous one: The input is + processed by the `expand' utility to change TABs into spaces, so + the widths compared are actually the right-margin columns, as + opposed to the number of input characters on each line. * Print every line that has at least one field: @@ -2029,8 +2041,8 @@ summarize, select, and rearrange the output of another utility. It uses features that haven't been covered yet, so don't worry if you don't understand all the details: - LC_ALL=C ls -l | awk '$6 == "Nov" { sum += $5 } - END { print sum }' + ls -l | awk '$6 == "Nov" { sum += $5 } + END { print sum }' This command prints the total number of bytes in all the files in the current directory that were last modified in November (of any year). @@ -2210,7 +2222,7 @@ determining the type of a variable, and array sorting. As we develop our presentation of the `awk' language, we introduce most of the variables and many of the functions. They are described -systematically in *note Built-in Variables::, and *note Built-in::. +systematically in *note Built-in Variables::, and in *note Built-in::. File: gawk.info, Node: When, Next: Intro Summary, Prev: Other Features, Up: Getting Started @@ -2237,21 +2249,18 @@ edit-compile-test-debug cycle of software development. retargetable assembler for eight-bit microprocessors (*note Glossary::, for more information), and a microcode assembler for a special-purpose Prolog computer. While the original `awk''s capabilities were strained -by tasks of such complexity, modern versions are more capable. Even -Brian Kernighan's version of `awk' has fewer predefined limits, and -those that it has are much larger than they used to be. +by tasks of such complexity, modern versions are more capable. If you find yourself writing `awk' scripts of more than, say, a few hundred lines, you might consider using a different programming language. The shell is good at string and pattern matching; in -addition, it allows powerful use of the system utilities. More -conventional languages, such as C, C++, and Java, offer better -facilities for system programming and for managing the complexity of -large programs. Python offers a nice balance between high-level ease -of programming and access to system facilities. Programs in these -languages may require more lines of source code than the equivalent -`awk' programs, but they are easier to maintain and usually run more -efficiently. +addition, it allows powerful use of the system utilities. Python +offers a nice balance between high-level ease of programming and access +to system facilities.(1) + + ---------- Footnotes ---------- + + (1) Other popular scripting languages include Ruby and Perl. File: gawk.info, Node: Intro Summary, Prev: When, Up: Getting Started @@ -2261,6 +2270,9 @@ File: gawk.info, Node: Intro Summary, Prev: When, Up: Getting Started * Programs in `awk' consist of PATTERN-ACTION pairs. + * An ACTION without a PATTERN always runs. The default ACTION for a + pattern without one is `{ print $0 }'. + * Use either `awk 'PROGRAM' FILES' or `awk -f PROGRAM-FILE FILES' to run `awk'. @@ -2415,9 +2427,9 @@ The following list describes options mandated by the POSIX standard: `-c' `--traditional' Specify "compatibility mode", in which the GNU extensions to the - `awk' language are disabled, so that `gawk' behaves just like - Brian Kernighan's version `awk'. *Note POSIX/GNU::, which - summarizes the extensions. Also see *note Compatibility Mode::. + `awk' language are disabled, so that `gawk' behaves just like BWK + `awk'. *Note POSIX/GNU::, which summarizes the extensions. Also + see *note Compatibility Mode::. `-C' `--copyright' @@ -2470,9 +2482,9 @@ The following list describes options mandated by the POSIX standard: This option is particularly necessary for World Wide Web CGI applications that pass arguments through the URL; using this option prevents a malicious (or other) user from passing in - options, assignments, or `awk' source code (via `--source') to the - CGI application. This option should be used with `#!' scripts - (*note Executable Scripts::), like so: + options, assignments, or `awk' source code (via `-e') to the CGI + application. This option should be used with `#!' scripts (*note + Executable Scripts::), like so: #! /usr/local/bin/gawk -E @@ -2501,8 +2513,8 @@ The following list describes options mandated by the POSIX standard: this option is intended to be used with code libraries, `gawk' does not recognize such files as constituting main program input. Thus, after processing an `-i' argument, `gawk' still expects to - find the main source code via the `-f' option or on the - command-line. + find the main source code via the `-f' option or on the command + line. `-l' EXT `--load' EXT @@ -2519,7 +2531,7 @@ The following list describes options mandated by the POSIX standard: `-L'[VALUE] `--lint'[`='VALUE] Warn about constructs that are dubious or nonportable to other - `awk' implementations. No space is allowed between the `-D' and + `awk' implementations. No space is allowed between the `-L' and VALUE, if VALUE is supplied. Some warnings are issued when `gawk' first reads your program. Others are issued at runtime, as your program executes. With an optional argument of `fatal', lint @@ -2597,7 +2609,7 @@ The following list describes options mandated by the POSIX standard: * Newlines are not allowed after `?' or `:' (*note Conditional Exp::). - * Specifying `-Ft' on the command-line does not set the value + * Specifying `-Ft' on the command line does not set the value of `FS' to be a single TAB character (*note Field Separators::). @@ -2660,16 +2672,14 @@ standard input but then you will not be able to also use the standard input as a source of data.) Because it is clumsy using the standard `awk' mechanisms to mix -source file and command-line `awk' programs, `gawk' provides the -`--source' option. This does not require you to pre-empt the standard -input for your source code; it allows you to easily mix command-line -and library source code (*note AWKPATH Variable::). As with `-f', the -`--source' and `--include' options may also be used multiple times on -the command line. +source file and command-line `awk' programs, `gawk' provides the `-e' +option. This does not require you to pre-empt the standard input for +your source code; it allows you to easily mix command-line and library +source code (*note AWKPATH Variable::). As with `-f', the `-e' and `-i' +options may also be used multiple times on the command line. - If no `-f' or `--source' option is specified, then `gawk' uses the -first non-option command-line argument as the text of the program -source code. + If no `-f' or `-e' option is specified, then `gawk' uses the first +non-option command-line argument as the text of the program source code. If the environment variable `POSIXLY_CORRECT' exists, then `gawk' behaves in strict POSIX mode, exactly as if you had supplied `--posix'. @@ -2718,6 +2728,10 @@ arguments, including variable assignments, are included. As each element of `ARGV' is processed, `gawk' sets the variable `ARGIND' to the index in `ARGV' of the current element. + Changing `ARGC' and `ARGV' in your `awk' program lets you control +how `awk' processes the input files; this is described in more detail +in *note ARGC and ARGV::. + The distinction between file name arguments and variable-assignment arguments is made when `awk' is about to open the next input file. At that point in execution, it checks the file name to see whether it is @@ -2779,7 +2793,7 @@ with `getline' (*note Getline/File::). In addition, `gawk' allows you to specify the special file name `/dev/stdin', both on the command line and with `getline'. Some other versions of `awk' also support this, but it is not standard. (Some -operating systems provide a `/dev/stdin' file in the file system; +operating systems provide a `/dev/stdin' file in the filesystem; however, `gawk' always processes this file name itself.) @@ -2805,7 +2819,7 @@ File: gawk.info, Node: AWKPATH Variable, Next: AWKLIBPATH Variable, Up: Envir ---------------------------------------- The previous minor node described how `awk' program files can be named -on the command-line with the `-f' option. In most `awk' +on the command line with the `-f' option. In most `awk' implementations, you must supply a precise path name for each program file, unless the file is in the current directory. But in `gawk', if the file name supplied to the `-f' or `-i' options does not contain a @@ -2824,7 +2838,7 @@ in a standard directory in the default path and then specified on the command line with a short file name. Otherwise, the full file name would have to be typed for each file. - By using the `-i' option, or the `--source' and `-f' options, your + By using the `-i' option, or the `-e' and `-f' options, your command-line `awk' programs can use facilities in `awk' library files (*note Library Functions::). Path searching is not done if `gawk' is in compatibility mode. This is true for both `--traditional' and @@ -2892,7 +2906,7 @@ they are more specialized. Those in the following list are meant to be used by regular users. `POSIXLY_CORRECT' - Causes `gawk' to switch POSIX compatibility mode, disabling all + Causes `gawk' to switch to POSIX compatibility mode, disabling all traditional and GNU extensions. *Note Options::. `GAWK_SOCK_RETRIES' @@ -2920,7 +2934,7 @@ change. The variables are: the value should be a number, and `gawk' uses that number as the size of the buffer to allocate. (When this variable is not set, `gawk' uses the smaller of the file's size and the "default" - blocksize, which is usually the file systems I/O blocksize.) + blocksize, which is usually the filesystems I/O blocksize.) `AWK_HASH' If this variable exists with a value of `gst', `gawk' switches to @@ -3149,9 +3163,9 @@ File: gawk.info, Node: Invoking Summary, Prev: Undocumented, Up: Invoking Gaw * Use either `awk 'PROGRAM' FILES' or `awk -f PROGRAM-FILE FILES' to run `awk'. - * The three standard `awk' options are `-f', `-F' and `-v'. `gawk' - supplies these and many others, as well as corresponding GNU-style - long options. + * The three standard options for all versions of `awk' are `-f', + `-F' and `-v'. `gawk' supplies these and many others, as well as + corresponding GNU-style long options. * Non-option command-line arguments are usually treated as file names, unless they have the form `VAR=VALUE', in which case they @@ -3197,7 +3211,7 @@ that matches every input record whose text belongs to that set. The simplest regular expression is a sequence of letters, numbers, or both. Such a regexp matches any string that contains that sequence. Thus, the regexp `foo' matches any string containing `foo'. Therefore, the -pattern `/foo/' matches any input record containing the three +pattern `/foo/' matches any input record containing the three adjacent characters `foo' _anywhere_ in the record. Other kinds of regexps let you specify more complicated classes of strings. @@ -3207,10 +3221,10 @@ you specify more complicated classes of strings. * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between `[...]'. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. @@ -3337,26 +3351,34 @@ apply to both string constants and regexp constants: `\xHH...' The hexadecimal value HH, where HH stands for a sequence of - hexadecimal digits (`0'-`9', and either `A'-`F' or `a'-`f'). Like - the same construct in ISO C, the escape sequence continues until - the first nonhexadecimal digit is seen. (c.e.) However, using - more than two hexadecimal digits produces undefined results. (The - `\x' escape sequence is not allowed in POSIX `awk'.) + hexadecimal digits (`0'-`9', and either `A'-`F' or `a'-`f'). A + maximum of two digts are allowed after the `\x'. Any further + hexadecimal digits are treated as simple letters or numbers. + (c.e.) + + CAUTION: In ISO C, the escape sequence continues until the + first nonhexadecimal digit is seen. For many years, `gawk' + would continue incorporating hexadecimal digits into the + value until a non-hexadecimal digit or the end of the string + was encountered. However, using more than two hexadecimal + digits produces `\/' A literal slash (necessary for regexp constants only). This sequence is used when you want to write a regexp constant that - contains a slash. Because the regexp is delimited by slashes, you - need to escape the slash that is part of the pattern, in order to + contains a slash (such as `/.*:\/home\/[[:alnum:]]+:.*/'; the + `[[:alnum:]]' notation is discussed shortly, in *note Bracket + Expressions::). Because the regexp is delimited by slashes, you + need to escape any slash that is part of the pattern, in order to tell `awk' to keep processing the rest of the regexp. `\"' A literal double quote (necessary for string constants only). This sequence is used when you want to write a string constant - that contains a double quote. Because the string is delimited by - double quotes, you need to escape the quote that is part of the - string, in order to tell `awk' to keep processing the rest of the - string. + that contains a double quote (such as `"He said \"hi!\" to her."'). + Because the string is delimited by double quotes, you need to + escape any quote that is part of the string, in order to tell + `awk' to keep processing the rest of the string. In `gawk', a number of additional two-character sequences that begin with a backslash have special meaning in regexps. *Note GNU Regexp @@ -3391,12 +3413,12 @@ is not one of the characters previously listed, POSIX `awk' purposely leaves what happens as undefined. There are two choices: Strip the backslash out - This is what Brian Kernighan's `awk' and `gawk' both do. For - example, `"a\qc"' is the same as `"aqc"'. (Because this is such - an easy bug both to introduce and to miss, `gawk' warns you about - it.) Consider `FS = "[ \t]+\|[ \t]+"' to use vertical bars - surrounded by whitespace as the field separator. There should be - two backslashes in the string: `FS = "[ \t]+\\|[ \t]+"'.) + This is what BWK `awk' and `gawk' both do. For example, `"a\qc"' + is the same as `"aqc"'. (Because this is such an easy bug both to + introduce and to miss, `gawk' warns you about it.) Consider `FS = + "[ \t]+\|[ \t]+"' to use vertical bars surrounded by whitespace as + the field separator. There should be two backslashes in the + string: `FS = "[ \t]+\\|[ \t]+"'.) Leave the backslash alone Some other `awk' implementations do this. In such @@ -3488,9 +3510,10 @@ sequences and that are not listed in the table stand for themselves: `|' This is the "alternation operator" and it is used to specify alternatives. The `|' has the lowest precedence of all the regular - expression operators. For example, `^P|[[:digit:]]' matches any - string that matches either `^P' or `[[:digit:]]'. This means it - matches any string that starts with `P' or contains a digit. + expression operators. For example, `^P|[aeiouy]' matches any + string that matches either `^P' or `[aeiouy]'. This means it + matches any string that starts with `P' or contains (anywhere + within it) a lowercase English vowel. The alternation applies to the largest possible regexps on either side. @@ -3510,22 +3533,20 @@ sequences and that are not listed in the table stand for themselves: matches of one `p' followed by any number of `h's. This also matches just `p' if no `h's are present. - The `*' repeats the _smallest_ possible preceding expression. - (Use parentheses if you want to repeat a larger expression.) It - finds as many repetitions as possible. For example, `awk - '/\(c[ad][ad]*r x\)/ { print }' sample' prints every record in - `sample' containing a string of the form `(car x)', `(cdr x)', - `(cadr x)', and so on. Notice the escaping of the parentheses by - preceding them with backslashes. + There are two subtle points to understand about how `*' works. + First, the `*' applies only to the single preceding regular + expression component (e.g., in `ph*', it applies just to the `h'). + To cause `*' to apply to a larger sub-expression, use parentheses: + `(ph)*' matches `ph', `phph', `phphph' and so on. + + Second, `*' finds as many repetititons as possible. If the text to + be matched is `phhhhhhhhhhhhhhooey', `ph*' matches all of the `h's. `+' This symbol is similar to `*', except that the preceding expression must be matched at least once. This means that `wh+y' would match `why' and `whhy', but not `wy', whereas `wh*y' would - match all three. The following is a simpler way of writing the - last `*' example: - - awk '/\(c[ad]+r x\)/ { print }' sample + match all three. `?' This symbol is similar to `*', except that the preceding @@ -3595,7 +3616,7 @@ list". regexp operator or function. -File: gawk.info, Node: Bracket Expressions, Next: GNU Regexp Operators, Prev: Regexp Operators, Up: Regexp +File: gawk.info, Node: Bracket Expressions, Next: Leftmost Longest, Prev: Regexp Operators, Up: Regexp 3.4 Using Bracket Expressions ============================= @@ -3616,7 +3637,9 @@ expression, put a `\' in front of it. For example: [d\]] -matches either `d' or `]'. +matches either `d' or `]'. Additionally, if you place `]' right after +the opening `[', the closing bracket is treated as one of the +characters to be matched. This treatment of `\' in bracket expressions is compatible with other `awk' implementations and is also mandated by POSIX. The regular @@ -3698,9 +3721,118 @@ Equivalence classes classes. -File: gawk.info, Node: GNU Regexp Operators, Next: Case-sensitivity, Prev: Bracket Expressions, Up: Regexp +File: gawk.info, Node: Leftmost Longest, Next: Computed Regexps, Prev: Bracket Expressions, Up: Regexp + +3.5 How Much Text Matches? +========================== + +Consider the following: + + echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }' + + This example uses the `sub()' function (which we haven't discussed +yet; *note String Functions::) to make a change to the input record. +Here, the regexp `/a+/' indicates "one or more `a' characters," and the +replacement text is `<A>'. + + The input contains four `a' characters. `awk' (and POSIX) regular +expressions always match the leftmost, _longest_ sequence of input +characters that can match. Thus, all four `a' characters are replaced +with `<A>' in this example: + + $ echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }' + -| <A>bcd + + For simple match/no-match tests, this is not so important. But when +doing text matching and substitutions with the `match()', `sub()', +`gsub()', and `gensub()' functions, it is very important. *Note String +Functions::, for more information on these functions. Understanding +this principle is also important for regexp-based record and field +splitting (*note Records::, and also *note Field Separators::). + + +File: gawk.info, Node: Computed Regexps, Next: GNU Regexp Operators, Prev: Leftmost Longest, Up: Regexp + +3.6 Using Dynamic Regexps +========================= + +The righthand side of a `~' or `!~' operator need not be a regexp +constant (i.e., a string of characters between slashes). It may be any +expression. The expression is evaluated and converted to a string if +necessary; the contents of the string are then used as the regexp. A +regexp computed in this way is called a "dynamic regexp" or a "computed +regexp": + + BEGIN { digits_regexp = "[[:digit:]]+" } + $0 ~ digits_regexp { print } + +This sets `digits_regexp' to a regexp that describes one or more digits, +and tests whether the input record matches this regexp. + + NOTE: When using the `~' and `!~' operators, there is a difference + between a regexp constant enclosed in slashes and a string + constant enclosed in double quotes. If you are going to use a + string constant, you have to understand that the string is, in + essence, scanned _twice_: the first time when `awk' reads your + program, and the second time when it goes to match the string on + the lefthand side of the operator with the pattern on the right. + This is true of any string-valued expression (such as + `digits_regexp', shown previously), not just string constants. + + What difference does it make if the string is scanned twice? The +answer has to do with escape sequences, and particularly with +backslashes. To get a backslash into a regular expression inside a +string, you have to type two backslashes. + + For example, `/\*/' is a regexp constant for a literal `*'. Only +one backslash is needed. To do the same thing with a string, you have +to type `"\\*"'. The first backslash escapes the second one so that +the string actually contains the two characters `\' and `*'. + + Given that you can use both regexp and string constants to describe +regular expressions, which should you use? The answer is "regexp +constants," for several reasons: + + * String constants are more complicated to write and more difficult + to read. Using regexp constants makes your programs less + error-prone. Not understanding the difference between the two + kinds of constants is a common source of errors. + + * It is more efficient to use regexp constants. `awk' can note that + you have supplied a regexp and store it internally in a form that + makes pattern matching more efficient. When using a string + constant, `awk' must first convert the string into this internal + form and then perform the pattern matching. + + * Using regexp constants is better form; it shows clearly that you + intend a regexp match. + + Using `\n' in Bracket Expressions of Dynamic Regexps + + Some versions of `awk' do not allow the newline character to be used +inside a bracket expression for a dynamic regexp: + + $ awk '$0 ~ "[ \t\n]"' + error--> awk: newline in character class [ + error--> ]... + error--> source line number 1 + error--> context is + error--> >>> <<< + + But a newline in a regexp constant works with no problem: + + $ awk '$0 ~ /[ \t\n]/' + here is a sample line + -| here is a sample line + Ctrl-d + + `gawk' does not have this problem, and it isn't likely to occur +often in practice, but it's worth noting for future reference. + + +File: gawk.info, Node: GNU Regexp Operators, Next: Case-sensitivity, Prev: Computed Regexps, Up: Regexp -3.5 `gawk'-Specific Regexp Operators +3.7 `gawk'-Specific Regexp Operators ==================================== GNU software that deals with regular expressions provides a number of @@ -3784,9 +3916,9 @@ No options Traditional Unix `awk' regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (`[[:alnum:]]', etc.) are supported, as - Brian Kernighan's `awk' does support them. Characters described - by octal and hexadecimal escape sequences are treated literally, - even if they represent regexp metacharacters. + BWK `awk' does support them. Characters described by octal and + hexadecimal escape sequences are treated literally, even if they + represent regexp metacharacters. `--re-interval' Allow interval expressions in regexps, if `--traditional' has been @@ -3794,9 +3926,9 @@ No options default. -File: gawk.info, Node: Case-sensitivity, Next: Leftmost Longest, Prev: GNU Regexp Operators, Up: Regexp +File: gawk.info, Node: Case-sensitivity, Next: Regexp Summary, Prev: GNU Regexp Operators, Up: Regexp -3.6 Case Sensitivity in Matching +3.8 Case Sensitivity in Matching ================================ Case is normally significant in regular expressions, both when matching @@ -3869,116 +4001,7 @@ obscure and we don't recommend it. means that `gawk' does the right thing. -File: gawk.info, Node: Leftmost Longest, Next: Computed Regexps, Prev: Case-sensitivity, Up: Regexp - -3.7 How Much Text Matches? -========================== - -Consider the following: - - echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }' - - This example uses the `sub()' function (which we haven't discussed -yet; *note String Functions::) to make a change to the input record. -Here, the regexp `/a+/' indicates "one or more `a' characters," and the -replacement text is `<A>'. - - The input contains four `a' characters. `awk' (and POSIX) regular -expressions always match the leftmost, _longest_ sequence of input -characters that can match. Thus, all four `a' characters are replaced -with `<A>' in this example: - - $ echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }' - -| <A>bcd - - For simple match/no-match tests, this is not so important. But when -doing text matching and substitutions with the `match()', `sub()', -`gsub()', and `gensub()' functions, it is very important. *Note String -Functions::, for more information on these functions. Understanding -this principle is also important for regexp-based record and field -splitting (*note Records::, and also *note Field Separators::). - - -File: gawk.info, Node: Computed Regexps, Next: Regexp Summary, Prev: Leftmost Longest, Up: Regexp - -3.8 Using Dynamic Regexps -========================= - -The righthand side of a `~' or `!~' operator need not be a regexp -constant (i.e., a string of characters between slashes). It may be any -expression. The expression is evaluated and converted to a string if -necessary; the contents of the string are then used as the regexp. A -regexp computed in this way is called a "dynamic regexp" or a "computed -regexp": - - BEGIN { digits_regexp = "[[:digit:]]+" } - $0 ~ digits_regexp { print } - -This sets `digits_regexp' to a regexp that describes one or more digits, -and tests whether the input record matches this regexp. - - NOTE: When using the `~' and `!~' operators, there is a difference - between a regexp constant enclosed in slashes and a string - constant enclosed in double quotes. If you are going to use a - string constant, you have to understand that the string is, in - essence, scanned _twice_: the first time when `awk' reads your - program, and the second time when it goes to match the string on - the lefthand side of the operator with the pattern on the right. - This is true of any string-valued expression (such as - `digits_regexp', shown previously), not just string constants. - - What difference does it make if the string is scanned twice? The -answer has to do with escape sequences, and particularly with -backslashes. To get a backslash into a regular expression inside a -string, you have to type two backslashes. - - For example, `/\*/' is a regexp constant for a literal `*'. Only -one backslash is needed. To do the same thing with a string, you have -to type `"\\*"'. The first backslash escapes the second one so that -the string actually contains the two characters `\' and `*'. - - Given that you can use both regexp and string constants to describe -regular expressions, which should you use? The answer is "regexp -constants," for several reasons: - - * String constants are more complicated to write and more difficult - to read. Using regexp constants makes your programs less - error-prone. Not understanding the difference between the two - kinds of constants is a common source of errors. - - * It is more efficient to use regexp constants. `awk' can note that - you have supplied a regexp and store it internally in a form that - makes pattern matching more efficient. When using a string - constant, `awk' must first convert the string into this internal - form and then perform the pattern matching. - - * Using regexp constants is better form; it shows clearly that you - intend a regexp match. - - Using `\n' in Bracket Expressions of Dynamic Regexps - - Some versions of `awk' do not allow the newline character to be used -inside a bracket expression for a dynamic regexp: - - $ awk '$0 ~ "[ \t\n]"' - error--> awk: newline in character class [ - error--> ]... - error--> source line number 1 - error--> context is - error--> >>> <<< - - But a newline in a regexp constant works with no problem: - - $ awk '$0 ~ /[ \t\n]/' - here is a sample line - -| here is a sample line - Ctrl-d - - `gawk' does not have this problem, and it isn't likely to occur -often in practice, but it's worth noting for future reference. - - -File: gawk.info, Node: Regexp Summary, Prev: Computed Regexps, Up: Regexp +File: gawk.info, Node: Regexp Summary, Prev: Case-sensitivity, Up: Regexp 3.9 Summary =========== @@ -3987,7 +4010,7 @@ File: gawk.info, Node: Regexp Summary, Prev: Computed Regexps, Up: Regexp `awk', regular expression constants are written enclosed between slashes: `/'...`/'. - * Regexp constants may be used by standalone in patterns and in + * Regexp constants may be used standalone in patterns and in conditional expressions, or as part of matching expressions using the `~' and `!~' operators. @@ -4011,8 +4034,8 @@ File: gawk.info, Node: Regexp Summary, Prev: Computed Regexps, Up: Regexp extent of the match, such as for text substitution and when the record separator is a regexp. - * Matching expressions may use dynamic regexps; that is string values - treated as regular expressions. + * Matching expressions may use dynamic regexps, that is, string + values treated as regular expressions. @@ -4053,7 +4076,7 @@ have to be named on the `awk' command line (*note Getline::). * Getline:: Reading files under explicit program control using the `getline' function. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on the +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -4064,13 +4087,13 @@ File: gawk.info, Node: Records, Next: Fields, Up: Reading Files 4.1 How Input Is Split into Records =================================== -The `awk' utility divides the input for your `awk' program into records -and fields. `awk' keeps track of the number of records that have been -read so far from the current input file. This value is stored in a -built-in variable called `FNR'. It is reset to zero when a new file is -started. Another built-in variable, `NR', records the total number of -input records read so far from all data files. It starts at zero, but -is never automatically reset to zero. +`awk' divides the input for your program into records and fields. It +keeps track of the number of records that have been read so far from +the current input file. This value is stored in a built-in variable +called `FNR' which is reset to zero when a new file is started. +Another built-in variable, `NR', records the total number of input +records read so far from all data files. It starts at zero, but is +never automatically reset to zero. * Menu: @@ -4235,16 +4258,16 @@ trailing whitespace: $ echo record 1 AAAA record 2 BBBB record 3 | > gawk 'BEGIN { RS = "\n|( *[[:upper:]]+ *)" } - > { print "Record =", $0, "and RT =", RT }' - -| Record = record 1 and RT = AAAA - -| Record = record 2 and RT = BBBB - -| Record = record 3 and RT = - -| + > { print "Record =", $0,"and RT = [" RT "]" }' + -| Record = record 1 and RT = [ AAAA ] + -| Record = record 2 and RT = [ BBBB ] + -| Record = record 3 and RT = [ + -| ] -The final line of output has an extra blank line. This is because the -value of `RT' is a newline, and the `print' statement supplies its own -terminating newline. *Note Simple Sed::, for a more useful example of -`RS' as a regexp and `RT'. +The square brackets delineate the contents of `RT', letting you see the +leading and trailing whitespace. The final value of `RT' `RT' is a +newline. *Note Simple Sed::, for a more useful example of `RS' as a +regexp and `RT'. If you set `RS' to a regular expression that allows optional trailing text, such as `RS = "abc(XYZ)?"' it is possible, due to @@ -4586,7 +4609,7 @@ File: gawk.info, Node: Field Separators, Next: Constant Size, Prev: Changing * Default Field Splitting:: How fields are normally separated. * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting `FS' from the command-line. +* Command Line Field Separator:: Setting `FS' from the command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -4730,9 +4753,8 @@ field separator a new string? It turns out that different `awk' versions answer this question differently, and you should not rely on any specific behavior in your programs. (d.c.) - As a point of information, Brian Kernighan's `awk' allows `^' to -match only at the beginning of the record. `gawk' also works this way. -For example: + As a point of information, BWK `awk' allows `^' to match only at the +beginning of the record. `gawk' also works this way. For example: $ echo 'xxAA xxBxx C' | > gawk -F '(^x+)|( +)' '{ for (i = 1; i <= NF; i++) @@ -4805,7 +4827,8 @@ argument to `-F' is `t', then `FS' is set to the TAB character. If you type `-F\t' at the shell, without any quotes, the `\' gets deleted, so `awk' figures that you really want your fields to be separated with TABs and not `t's. Use `-v FS="t"' or `-F"[t]"' on the command line if -you really do want to separate your fields with `t's. +you really do want to separate your fields with `t's. Use `-F '\t'' +when not in compatibility mode to specify that TABs separate fields. As an example, let's use an `awk' program file called `edu.awk' that contains the pattern `/edu/' and the action `print $1': @@ -4925,8 +4948,8 @@ which usually prints: root -on an incorrect implementation of `awk', while `gawk' prints something -like: +on an incorrect implementation of `awk', while `gawk' prints the full +first line of the file, something like: root:nSijPlPhZZwgE:0:0:Root:/: @@ -5006,7 +5029,7 @@ calculated idle time: BEGIN { FIELDWIDTHS = "9 6 10 6 7 7 35" } NR > 2 { idle = $4 - sub(/^ */, "", idle) # strip leading spaces + sub(/^ +/, "", idle) # strip leading spaces if (idle == "") idle = 0 if (idle ~ /:/) { @@ -5137,8 +5160,10 @@ would be to remove the quotes when they occur, with something like this: As with `FS', the `IGNORECASE' variable (*note User-modified::) affects field splitting with `FPAT'. - Similar to `FIELDWIDTHS', the value of `PROCINFO["FS"]' will be -`"FPAT"' if content-based field splitting is being used. + Assigning a value to `FPAT' overrides field splitting with `FS' and +with `FIELDWIDTHS'. Similar to `FIELDWIDTHS', the value of +`PROCINFO["FS"]' will be `"FPAT"' if content-based field splitting is +being used. NOTE: Some programs export CSV data that contains embedded newlines between the double quotes. `gawk' provides no way to @@ -5156,6 +5181,11 @@ changed the first `+' to `*') allows fields to be empty: Finally, the `patsplit()' function makes the same functionality available for splitting regular strings (*note String Functions::). + To recap, `gawk' provides three independent methods to split input +records into fields. `gawk' uses whichever mechanism was last chosen +based on which of the three variables--`FS', `FIELDWIDTHS', and +`FPAT'--was last assigned to. + ---------- Footnotes ---------- (1) At least, we don't know of one. @@ -5318,8 +5348,8 @@ yet. Therefore, come back and study the `getline' command _after_ you have reviewed the rest of this Info file and have a good knowledge of how `awk' works. - The `getline' command returns one if it finds a record and zero if -it encounters the end of the file. If there is some error in getting a + The `getline' command returns 1 if it finds a record and 0 if it +encounters the end of the file. If there is some error in getting a record, such as a file that cannot be opened, then `getline' returns -1. In this case, `gawk' sets the variable `ERRNO' to a string describing the error that occurred. @@ -5358,35 +5388,47 @@ input record and split it up into fields. This is useful if you've finished processing the current record, but want to do some special processing on the next record _right now_. For example: + # Remove text between /* and */, inclusive { - if ((t = index($0, "/*")) != 0) { - # value of `tmp' will be "" if t is 1 - tmp = substr($0, 1, t - 1) - u = index(substr($0, t + 2), "*/") - offset = t + 2 - while (u == 0) { - if (getline <= 0) { + if ((i = index($0, "/*")) != 0) { + out = substr($0, 1, i - 1) # leading part of the string + rest = substr($0, i + 2) # ... */ ... + j = index(rest, "*/") # is */ in trailing part? + if (j > 0) { + rest = substr(rest, j + 2) # remove comment + } else { + while (j == 0) { + # get more text + if (getline <= 0) { m = "unexpected EOF or error" m = (m ": " ERRNO) print m > "/dev/stderr" exit - } - u = index($0, "*/") - offset = 0 - } - # substr() expression will be "" if */ - # occurred at end of line - $0 = tmp substr($0, offset + u + 2) - } - print $0 + } + # build up the line using string concatenation + rest = rest $0 + j = index(rest, "*/") # is */ in trailing part? + if (j != 0) { + rest = substr(rest, j + 2) + break + } + } + } + # build up the output line using string concatenation + $0 = out rest + } + print $0 } This `awk' program deletes C-style comments (`/* ... */') from the -input. By replacing the `print $0' with other statements, you could -perform more complicated processing on the decommented input, such as -searching for matches of a regular expression. (This program has a -subtle problem--it does not work if one comment ends and another begins -on the same line.) +input. It uses a number of features we haven't covered yet, including +string concatenation (*note Concatenation::) and the `index()' and +`substr()' built-in functions (*note String Functions::). By replacing +the `print $0' with other statements, you could perform more +complicated processing on the decommented input, such as searching for +matches of a regular expression. (This program has a subtle +problem--it does not work if one comment ends and another begins on the +same line.) This form of the `getline' command sets `NF', `NR', `FNR', `RT', and the value of `$0'. @@ -5581,10 +5623,10 @@ all `awk' implementations. NOTE: Unfortunately, `gawk' has not been consistent in its treatment of a construct like `"echo " "date" | getline'. Most versions, including the current version, treat it at as `("echo " - "date") | getline'. (This how Brian Kernighan's `awk' behaves.) - Some versions changed and treated it as `"echo " ("date" | - getline)'. (This is how `mawk' behaves.) In short, _always_ use - explicit parentheses, and then you won't have to worry. + "date") | getline'. (This how BWK `awk' behaves.) Some versions + changed and treated it as `"echo " ("date" | getline)'. (This is + how `mawk' behaves.) In short, _always_ use explicit parentheses, + and then you won't have to worry. File: gawk.info, Node: Getline/Variable/Pipe, Next: Getline/Coprocess, Prev: Getline/Pipe, Up: Getline @@ -5750,7 +5792,7 @@ VAR Table 4.1: `getline' Variants and What They Set -File: gawk.info, Node: Read Timeout, Next: Command line directories, Prev: Getline, Up: Reading Files +File: gawk.info, Node: Read Timeout, Next: Command-line directories, Prev: Getline, Up: Reading Files 4.10 Reading Input With A Timeout ================================= @@ -5844,7 +5886,7 @@ writing. (1) This assumes that standard input is the keyboard. -File: gawk.info, Node: Command line directories, Next: Input Summary, Prev: Read Timeout, Up: Reading Files +File: gawk.info, Node: Command-line directories, Next: Input Summary, Prev: Read Timeout, Up: Reading Files 4.11 Directories On The Command Line ==================================== @@ -5867,7 +5909,7 @@ error. usable data from an `awk' program. -File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command line directories, Up: Reading Files +File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-line directories, Up: Reading Files 4.12 Summary ============ @@ -5950,8 +5992,8 @@ File: gawk.info, Node: Input Exercises, Prev: Input Summary, Up: Reading File 2. *note Plain Getline::, presented a program to remove C-style comments (`/* ... */') from the input. That program does not work if one comment ends on one line and another one starts later on - the same line. Write a program that does handle multiple comments - on the line. + the same line. That can be fixed by making one simple change. + What is it? @@ -5989,7 +6031,7 @@ function. descriptors. * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. File: gawk.info, Node: Print, Next: Print Examples, Up: Printing @@ -6021,6 +6063,10 @@ you forget to use the double-quote characters, your text is taken as an `awk' expression, and you will probably get an error. Keep in mind that a space is printed between any two items. + Note that the `print' statement is a statement and not an +expression--you can't use it the pattern part of a pattern-action +statement, for example. + File: gawk.info, Node: Print Examples, Next: Output Separators, Prev: Print, Up: Printing @@ -6743,8 +6789,8 @@ to rename the files. It then sends the list to the shell for execution. File: gawk.info, Node: Special Files, Next: Close Files And Pipes, Prev: Redirection, Up: Printing -5.7 Special File Name in `gawk' -=============================== +5.7 Special File Names in `gawk' +================================ `gawk' provides a number of special file names that it interprets internally. These file names provide access to standard file @@ -6779,9 +6825,9 @@ message to standard error in an `awk' program is as follows: This works by opening a pipeline to a shell command that can access the standard error stream that it inherits from the `awk' process. This is -far from elegant, and it is also inefficient, because it requires a -separate process. So people writing `awk' programs often don't do -this. Instead, they send the error messages to the screen, like this: +far from elegant, and it also requires a separate process. So people +writing `awk' programs often don't do this. Instead, they send the +error messages to the screen, like this: print "Serious error detected!" > "/dev/tty" @@ -7047,7 +7093,7 @@ call. See the system manual pages for information on how to decode this value. -File: gawk.info, Node: Output Summary, Next: Output exercises, Prev: Close Files And Pipes, Up: Printing +File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Close Files And Pipes, Up: Printing 5.9 Summary =========== @@ -7073,7 +7119,7 @@ File: gawk.info, Node: Output Summary, Next: Output exercises, Prev: Close Fi -File: gawk.info, Node: Output exercises, Prev: Output Summary, Up: Printing +File: gawk.info, Node: Output Exercises, Prev: Output Summary, Up: Printing 5.10 Exercises ============== @@ -7278,8 +7324,9 @@ File: gawk.info, Node: Regexp Constants, Prev: Nondecimal-numbers, Up: Consta A regexp constant is a regular expression description enclosed in slashes, such as `/^beginning and end$/'. Most regexps used in `awk' programs are constant, but the `~' and `!~' matching operators can also -match computed or dynamic regexps (which are just ordinary strings or -variables that contain a regexp). +match computed or dynamic regexps (which are typically just ordinary +strings or variables that contain a regexp, but could be a more complex +expression). File: gawk.info, Node: Using Constant Regexps, Next: Variables, Prev: Constants, Up: Values @@ -7351,12 +7398,12 @@ For example: } In this example, the programmer wants to pass a regexp constant to -the user-defined function `mysub', which in turn passes it on to either -`sub()' or `gsub()'. However, what really happens is that the `pat' -parameter is either one or zero, depending upon whether or not `$0' -matches `/hi/'. `gawk' issues a warning when it sees a regexp constant -used as a parameter to a user-defined function, since passing a truth -value in this way is probably not what was intended. +the user-defined function `mysub()', which in turn passes it on to +either `sub()' or `gsub()'. However, what really happens is that the +`pat' parameter is either one or zero, depending upon whether or not +`$0' matches `/hi/'. `gawk' issues a warning when it sees a regexp +constant used as a parameter to a user-defined function, since passing +a truth value in this way is probably not what was intended. File: gawk.info, Node: Variables, Next: Conversion, Prev: Using Constant Regexps, Up: Values @@ -7372,7 +7419,7 @@ on the `awk' command line. * Menu: * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line and a +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. @@ -7796,13 +7843,14 @@ Otherwise, it's parsed as follows: => -12 (-24) => -12-24 - As mentioned earlier, when doing concatenation, _parenthesize_. -Otherwise, you're never quite sure what you'll get. + As mentioned earlier, when mixing concatenation with other +operators, _parenthesize_. Otherwise, you're never quite sure what +you'll get. ---------- Footnotes ---------- - (1) It happens that Brian Kernighan's `awk', `gawk' and `mawk' all -"get it right," but you should not rely on this. + (1) It happens that BWK `awk', `gawk' and `mawk' all "get it right," +but you should not rely on this. File: gawk.info, Node: Assignment Ops, Next: Increment Ops, Prev: Concatenation, Up: All Operators @@ -7966,8 +8014,8 @@ A workaround is: awk '/[=]=/' /dev/null - `gawk' does not have this problem; Brian Kernighan's `awk' and -`mawk' also do not (*note Other Versions::). + `gawk' does not have this problem; BWK `awk' and `mawk' also do not +(*note Other Versions::). File: gawk.info, Node: Increment Ops, Prev: Assignment Ops, Up: All Operators @@ -8131,16 +8179,11 @@ File: gawk.info, Node: Variable Typing, Next: Comparison Operators, Up: Typin 6.3.2.1 String Type Versus Numeric Type ....................................... -The 1992 POSIX standard introduced the concept of a "numeric string", -which is simply a string that looks like a number--for example, -`" +2"'. This concept is used for determining the type of a variable. -The type of the variable is important because the types of two variables -determine how they are compared. - - The various versions of the POSIX standard did not get the rules -quite right for several editions. Fortunately, as of at least the 2008 -standard (and possibly earlier), the standard has been fixed, and -variable typing follows these rules:(1) +The POSIX standard introduced the concept of a "numeric string", which +is simply a string that looks like a number--for example, `" +2"'. +This concept is used for determining the type of a variable. The type +of the variable is important because the types of two variables +determine how they are compared. Variable typing follows these rules: * A numeric constant or the result of a numeric operation has the NUMERIC attribute. @@ -8186,7 +8229,7 @@ operands, according to the following symmetric matrix: user input--should be treated as numeric, even though it is actually made of characters and is therefore also a string. Thus, for example, the string constant `" +3.14"', when it appears in program source code, -is a string--even though it looks numeric--and is _never_ treated as +is a string--even though it looks numeric--and is _never_ treated as a number for comparison purposes. In short, when one operand is a "pure" string, such as a string @@ -8218,11 +8261,6 @@ comparison between the two different constants is true, `0' otherwise: $ echo ' +3.14' | gawk '{ print $1 == 3.14 }' True -| 1 - ---------- Footnotes ---------- - - (1) `gawk' has followed these rules for many years, and it is -gratifying that the POSIX standard is also now correct. - File: gawk.info, Node: Comparison Operators, Next: POSIX String Comparison, Prev: Variable Typing, Up: Typing and Comparison @@ -8425,9 +8463,9 @@ because of the way they work. Evaluation of the full expression is "short-circuited" if the result can be determined part way through its evaluation. - Statements that use `&&' or `||' can be continued simply by putting -a newline after them. But you cannot put a newline in front of either -of these operators without using backslash continuation (*note + Statements that end with `&&' or `||' can be continued simply by +putting a newline after them. But you cannot put a newline in front of +either of these operators without using backslash continuation (*note Statements/Lines::). The actual value of an expression using the `!' operator is either @@ -8438,7 +8476,7 @@ following program is one way to print lines in between special bracketing lines: $1 == "START" { interested = ! interested; next } - interested == 1 { print } + interested { print } $1 == "END" { interested = ! interested; next } The variable `interested', as with all `awk' variables, starts out @@ -8448,6 +8486,14 @@ using `!'. The next rule prints lines as long as `interested' is true. When a line is seen whose first field is `END', `interested' is toggled back to false.(1) + Most commonly, the `!' operator is used in the conditions of `if' +and `while' statements, where it often makes more sense to phrase the +logic in the negative: + + if (! SOME CONDITION || SOME OTHER CONDITION) { + ... DO WHATEVER PROCESSING ... + } + NOTE: The `next' statement is discussed in *note Next Statement::. `next' tells `awk' to skip the rest of the rules, get the next record, and start processing the rules over again at the top. The @@ -8903,7 +8949,7 @@ precisely `li': `li'.) Contrast this with the following regular expression match, which accepts any record with a first field that contains `li': - $ awk '$1 ~ /foo/ { print $2 }' mail-list + $ awk '$1 ~ /li/ { print $2 }' mail-list -| 555-5553 -| 555-6699 @@ -9124,8 +9170,7 @@ number of fields from the last input record. Most probably due to an oversight, the standard does not say that `$0' is also preserved, although logically one would think that it should be. In fact, `gawk' does preserve the value of `$0' for use in `END' rules. Be aware, -however, that Brian Kernighan's `awk', and possibly other -implementations, do not. +however, that BWK `awk', and possibly other implementations, do not. The third point follows from the first two. The meaning of `print' inside a `BEGIN' or `END' rule is the same as always: `print $0'. If @@ -9607,29 +9652,36 @@ match to a given case is made, the case statement bodies execute until a `break', `continue', `next', `nextfile' or `exit' is encountered, or the end of the `switch' statement itself. For example: - switch (NR * 2 + 1) { - case 3: - case "11": - print NR - 1 - break - - case /2[[:digit:]]+/: - print NR - - default: - print NR + 1 - - case -1: - print NR * -1 + while ((c = getopt(ARGC, ARGV, "aksx")) != -1) { + switch (c) { + case "a": + # report size of all files + all_files = TRUE; + break + case "k": + BLOCK_SIZE = 1024 # 1K block size + break + case "s": + # do sums only + sum_only = TRUE + break + case "x": + # don't cross filesystems + fts_flags = or(fts_flags, FTS_XDEV) + break + case "?": + default: + usage() + break + } } Note that if none of the statements specified above halt execution of a matched `case' statement, execution falls through to the next -`case' until execution halts. In the above example, for any case value -starting with `2' followed by one or more digits, the `print' statement -is executed and then falls through into the `default' section, -executing its `print' statement. In turn, the -1 case will also be -executed since the `default' does not halt execution. +`case' until execution halts. In the above example, the `case' for +`"?"' falls through to the `default' case, which is to call a function +named `usage()'. (The `getopt()' function being called here is +described in *note Getopt Function::.) File: gawk.info, Node: Break Statement, Next: Continue Statement, Prev: Switch Statement, Up: Statements @@ -9686,8 +9738,8 @@ statement. This is discussed in *note Switch Statement::. loop or `switch'. However, although it was never documented, historical implementations of `awk' treated the `break' statement outside of a loop as if it were a `next' statement (*note Next -Statement::). (d.c.) Recent versions of Brian Kernighan's `awk' no -longer allow this usage, nor does `gawk'. +Statement::). (d.c.) Recent versions of BWK `awk' no longer allow +this usage, nor does `gawk'. File: gawk.info, Node: Continue Statement, Next: Next Statement, Prev: Break Statement, Up: Statements @@ -9730,15 +9782,16 @@ the previous example with the following `while' loop: print "" } -This program loops forever once `x' reaches 5. +This program loops forever once `x' reaches 5, since the increment +(`x++') is never reached. The `continue' statement has no special meaning with respect to the `switch' statement, nor does it have any meaning when used outside the body of a loop. Historical versions of `awk' treated a `continue' statement outside a loop the same way they treated a `break' statement outside a loop: as if it were a `next' statement (*note Next -Statement::). (d.c.) Recent versions of Brian Kernighan's `awk' no -longer work this way, nor does `gawk'. +Statement::). (d.c.) Recent versions of BWK `awk' no longer work this +way, nor does `gawk'. File: gawk.info, Node: Next Statement, Next: Nextfile Statement, Prev: Continue Statement, Up: Statements @@ -9809,7 +9862,7 @@ reset to one, and processing starts over with the first rule in the program. If the `nextfile' statement causes the end of the input to be reached, then the code in any `END' rules is executed. An exception to this is when `nextfile' is invoked during execution of any statement in -an `END' rule; In this case, it causes the program to stop immediately. +an `END' rule; in this case, it causes the program to stop immediately. *Note BEGIN/END::. The `nextfile' statement is useful when there are many data files to @@ -9819,10 +9872,10 @@ would have to continue scanning the unwanted records. The `nextfile' statement accomplishes this much more efficiently. In `gawk', execution of `nextfile' causes additional things to -happen: any `ENDFILE' rules are executed except in the case as -mentioned below, `ARGIND' is incremented, and any `BEGINFILE' rules are -executed. (`ARGIND' hasn't been introduced yet. *Note Built-in -Variables::.) +happen: any `ENDFILE' rules are executed if `gawk' is not currently in +an `END' or `BEGINFILE' rule, `ARGIND' is incremented, and any +`BEGINFILE' rules are executed. (`ARGIND' hasn't been introduced yet. +*Note Built-in Variables::.) With `gawk', `nextfile' is useful inside a `BEGINFILE' rule to skip over a file that would otherwise cause `gawk' to exit with a fatal @@ -9840,12 +9893,12 @@ listed in `ARGV'. standard. See the Austin Group website (http://austingroupbugs.net/view.php?id=607). - The current version of the Brian Kernighan's `awk', and `mawk' -(*note Other Versions::) also support `nextfile'. However, they don't -allow the `nextfile' statement inside function bodies (*note -User-defined::). `gawk' does; a `nextfile' inside a function body -reads the next record and starts processing it with the first rule in -the program, just as any other `nextfile' statement. + The current version of BWK `awk', and `mawk' (*note Other +Versions::) also support `nextfile'. However, they don't allow the +`nextfile' statement inside function bodies (*note User-defined::). +`gawk' does; a `nextfile' inside a function body reads the next record +and starts processing it with the first rule in the program, just as +any other `nextfile' statement. File: gawk.info, Node: Exit Statement, Prev: Nextfile Statement, Up: Statements @@ -10219,7 +10272,8 @@ Options::), they are not special. `FUNCTAB #' An array whose indices and corresponding values are the names of - all the user-defined or extension functions in the program. + all the built-in, user-defined and extension functions in the + program. NOTE: Attempting to use the `delete' statement with the `FUNCTAB' array causes a fatal error. Any attempt to assign @@ -10255,9 +10309,12 @@ Options::), they are not special. `"array"' The identifier is an array. + `"builtin"' + The identifier is a built-in function. + `"extension"' The identifier is an extension function loaded via - `@load'. + `@load' or `-l'. `"scalar"' The identifier is a scalar. @@ -10494,8 +10551,16 @@ elements from `ARGV' (*note Delete::). All of these actions are typically done in the `BEGIN' rule, before actual processing of the input begins. *Note Split Program::, and see *note Tee Program::, for examples of each way of removing elements from -`ARGV'. The following fragment processes `ARGV' in order to examine, -and then remove, command-line options: +`ARGV'. + + To actually get options into an `awk' program, end the `awk' options +with `--' and then supply the `awk' program's options, in the following +manner: + + awk -f myprog.awk -- -v -q file1 file2 ... + + The following fragment processes `ARGV' in order to examine, and +then remove, the above command-line options: BEGIN { for (i = 1; i < ARGC; i++) { @@ -10513,19 +10578,14 @@ and then remove, command-line options: } } - To actually get the options into the `awk' program, end the `awk' -options with `--' and then supply the `awk' program's options, in the -following manner: - - awk -f myprog -- -v -q file1 file2 ... + Ending the `awk' options with `--' isn't necessary in `gawk'. Unless +`--posix' has been specified, `gawk' silently puts any unrecognized +options into `ARGV' for the `awk' program to deal with. As soon as it +sees an unknown option, `gawk' stops looking for other options that it +might otherwise recognize. The previous command line with `gawk' would +be: - This is not necessary in `gawk'. Unless `--posix' has been -specified, `gawk' silently puts any unrecognized options into `ARGV' -for the `awk' program to deal with. As soon as it sees an unknown -option, `gawk' stops looking for other options that it might otherwise -recognize. The previous example with `gawk' would be: - - gawk -f myprog -q -v file1 file2 ... + gawk -f myprog.awk -q -v file1 file2 ... Because `-q' is not a valid `gawk' option, it and the following `-v' are passed on to the `awk' program. (*Note Getopt Function::, for an @@ -10696,7 +10756,8 @@ array element value: Index 0 Value 8 Index 2 Value "" -The pairs are shown in jumbled order because their order is irrelevant. +The pairs are shown in jumbled order because their order is +irrelevant.(1) One advantage of associative arrays is that new pairs can be added at any time. For example, suppose a tenth element is added to the array @@ -10725,9 +10786,10 @@ from English to French: Here we decided to translate the number one in both spelled-out and numeric form--thus illustrating that a single array can have both numbers and strings as indices. (In fact, array subscripts are always -strings; this is discussed in more detail in *note Numeric Array -Subscripts::.) Here, the number `1' isn't double-quoted, since `awk' -automatically converts it to a string. +strings. There are some subtleties to how numbers work when used as +array subscripts; this is discussed in more detail in *note Numeric +Array Subscripts::.) Here, the number `1' isn't double-quoted, since +`awk' automatically converts it to a string. The value of `IGNORECASE' has no effect upon array subscripting. The identical string value used to store an array element must be used @@ -10738,6 +10800,11 @@ starting at one. (*Note String Functions::.) `awk''s arrays are efficient--the time to access an element is independent of the number of elements in the array. + ---------- Footnotes ---------- + + (1) The ordering will vary among `awk' implementations, which +typically use hash tables to store array elements and values. + File: gawk.info, Node: Reference to Elements, Next: Assigning Elements, Prev: Array Intro, Up: Array Basics @@ -10772,8 +10839,9 @@ been assigned any value as well as elements that have been deleted # Check if "foo" exists in a: Incorrect! if (a["foo"] != "") ... - This is incorrect, since this will _create_ `a["foo"]' if it - didn't exist before! + This is incorrect for two reasons. First, it _creates_ `a["foo"]' + if it didn't exist before! Second, it is valid (if a bit unusual) + to set an array element equal to the empty string. To determine whether an element exists in an array at a certain index, use the following expression: @@ -10783,7 +10851,8 @@ index, use the following expression: This expression tests whether the particular index INDX exists, without the side effect of creating that element if it is not present. The expression has the value one (true) if `ARRAY[INDX]' exists and zero -(false) if it does not exist. For example, this statement tests +(false) if it does not exist. (We use INDX here, since `index' is the +name of a built-in function.) For example, this statement tests whether the array `frequencies' contains the index `2': if (2 in frequencies) @@ -10947,7 +11016,7 @@ all `awk' versions do so. Consider this program, named `loopcheck.awk': -| a -| is - Contrast this to Brian Kernighan's `awk': + Contrast this to BWK `awk': $ nawk -f loopcheck.awk -| loop @@ -11153,9 +11222,9 @@ at a time. `gawk' extension. As of September, 2012, it was accepted for inclusion into the POSIX standard. See the Austin Group website (http://austingroupbugs.net/view.php?id=544). This form of the - `delete' statement is also supported by Brian Kernighan's `awk' - and `mawk', as well as by a number of other implementations (*note - Other Versions::). + `delete' statement is also supported by BWK `awk' and `mawk', as + well as by a number of other implementations (*note Other + Versions::). The following statement provides a portable but nonobvious way to clear out an array:(1) @@ -11244,7 +11313,7 @@ might look like this: > line 2 > line 3' | awk '{ l[lines] = $0; ++lines } > END { - > for (i = lines-1; i >= 0; --i) + > for (i = lines - 1; i >= 0; i--) > print l[i] > }' -| line 3 @@ -11265,7 +11334,7 @@ following version of the program works correctly: { l[lines++] = $0 } END { - for (i = lines - 1; i >= 0; --i) + for (i = lines - 1; i >= 0; i--) print l[i] } @@ -11326,10 +11395,11 @@ multidimensional array, use the same operator (`in') that is used for single dimensional arrays. Write the whole sequence of indices in parentheses, separated by commas, as the left operand: - (SUBSCRIPT1, SUBSCRIPT2, ...) in ARRAY + if ((SUBSCRIPT1, SUBSCRIPT2, ...) in ARRAY) + ... - The following example treats its input as a two-dimensional array of -fields; it rotates this array 90 degrees clockwise and prints the + Here is an example that treats its input as a two-dimensional array +of fields; it rotates this array 90 degrees clockwise and prints the result. It assumes that all lines have the same number of elements: { @@ -11711,7 +11781,8 @@ brackets ([ ]): `log(X)' Return the natural logarithm of X, if X is positive; otherwise, - report an error. + return `NaN' ("not a number") on IEEE 754 systems. Additionally, + `gawk' prints a warning message when `x' is negative. `rand()' Return a random number. The values of `rand()' are uniformly @@ -11782,6 +11853,9 @@ brackets ([ ]): easy to keep track of the seeds in case you need to consistently reproduce sequences of random numbers. + POSIX does not specify the initial seed; it differs among `awk' + implementations. + ---------- Footnotes ---------- (1) The C version of `rand()' on many Unix systems is known to @@ -12289,11 +12363,11 @@ Options::): remaining in the string, counting from character START. If START is less than one, `substr()' treats it as if it was one. - (POSIX doesn't specify what to do in this case: Brian Kernighan's - `awk' acts this way, and therefore `gawk' does too.) If START is - greater than the number of characters in the string, `substr()' - returns the null string. Similarly, if LENGTH is present but less - than or equal to zero, the null string is returned. + (POSIX doesn't specify what to do in this case: BWK `awk' acts + this way, and therefore `gawk' does too.) If START is greater + than the number of characters in the string, `substr()' returns + the null string. Similarly, if LENGTH is present but less than or + equal to zero, the null string is returned. The string returned by `substr()' _cannot_ be assigned. Thus, it is a mistake to attempt to change a portion of a string, as shown @@ -12349,9 +12423,13 @@ File: gawk.info, Node: Gory Details, Up: String Functions 9.1.3.1 More About `\' and `&' with `sub()', `gsub()', and `gensub()' ..................................................................... -When using `sub()', `gsub()', or `gensub()', and trying to get literal -backslashes and ampersands into the replacement text, you need to -remember that there are several levels of "escape processing" going on. + CAUTION: This section has been known to cause headaches. You + might want to skip it upon first reading. + + When using `sub()', `gsub()', or `gensub()', and trying to get +literal backslashes and ampersands into the replacement text, you need +to remember that there are several levels of "escape processing" going +on. First, there is the "lexical" level, which is when `awk' reads your program and builds an internal copy of it to execute. Then there is @@ -12363,9 +12441,9 @@ come after a backslash. At the lexical level, it looks for the escape sequences listed in *note Escape Sequences::. Thus, for every `\' that `awk' processes at the runtime level, you must type two backslashes at the lexical level. When a character that is not valid for an escape -sequence follows the `\', Brian Kernighan's `awk' and `gawk' both -simply remove the initial `\' and put the next character into the -string. Thus, for example, `"a\qb"' is treated as `"aqb"'. +sequence follows the `\', BWK `awk' and `gawk' both simply remove the +initial `\' and put the next character into the string. Thus, for +example, `"a\qb"' is treated as `"aqb"'. At the runtime level, the various functions handle sequences of `\' and `&' differently. The situation is (sadly) somewhat complex. @@ -12377,13 +12455,13 @@ is illustrated in *note table-sub-escapes::. You type `sub()' sees `sub()' generates ------- --------- -------------- - `\&' `&' the matched text - `\\&' `\&' a literal `&' - `\\\&' `\&' a literal `&' - `\\\\&' `\\&' a literal `\&' - `\\\\\&' `\\&' a literal `\&' - `\\\\\\&' `\\\&' a literal `\\&' - `\\q' `\q' a literal `\q' + `\&' `&' The matched text + `\\&' `\&' A literal `&' + `\\\&' `\&' A literal `&' + `\\\\&' `\\&' A literal `\&' + `\\\\\&' `\\&' A literal `\&' + `\\\\\\&' `\\\&' A literal `\\&' + `\\q' `\q' A literal `\q' Table 9.1: Historical Escape Sequence Processing for `sub()' and `gsub()' @@ -12397,50 +12475,25 @@ backslashes entered at the lexical level.) The problem with the historical approach is that there is no way to get a literal `\' followed by the matched text. - The 1992 POSIX standard attempted to fix this problem. That standard -says that `sub()' and `gsub()' look for either a `\' or an `&' after -the `\'. If either one follows a `\', that character is output -literally. The interpretation of `\' and `&' then becomes as shown in -*note table-sub-posix-92::. - - You type `sub()' sees `sub()' generates - ------- --------- -------------- - `&' `&' the matched text - `\\&' `\&' a literal `&' - `\\\\&' `\\&' a literal `\', then the matched text - `\\\\\\&' `\\\&' a literal `\&' - -Table 9.2: 1992 POSIX Rules for `sub()' and `gsub()' Escape Sequence -Processing - -This appears to solve the problem. Unfortunately, the phrasing of the -standard is unusual. It says, in effect, that `\' turns off the special -meaning of any following character, but for anything other than `\' and -`&', such special meaning is undefined. This wording leads to two -problems: + Several editions of the POSIX standard attempted to fix this problem +but weren't successful. The details are irrelevant at this point in +time. - * Backslashes must now be doubled in the REPLACEMENT string, breaking - historical `awk' programs. - - * To make sure that an `awk' program is portable, _every_ character - in the REPLACEMENT string must be preceded with a backslash.(1) - - Because of the problems just listed, in 1996, the `gawk' maintainer -submitted proposed text for a revised standard that reverts to rules -that correspond more closely to the original existing practice. The -proposed rules have special cases that make it possible to produce a -`\' preceding the matched text. This is shown in *note -table-sub-proposed::. + At one point, the `gawk' maintainer submitted proposed text for a +revised standard that reverts to rules that correspond more closely to +the original existing practice. The proposed rules have special cases +that make it possible to produce a `\' preceding the matched text. +This is shown in *note table-sub-proposed::. You type `sub()' sees `sub()' generates ------- --------- -------------- - `\\\\\\&' `\\\&' a literal `\&' - `\\\\&' `\\&' a literal `\', followed by the matched text - `\\&' `\&' a literal `&' - `\\q' `\q' a literal `\q' + `\\\\\\&' `\\\&' A literal `\&' + `\\\\&' `\\&' A literal `\', followed by the matched text + `\\&' `\&' A literal `&' + `\\q' `\q' A literal `\q' `\\\\' `\\' `\\' -Table 9.3: Proposed Rules For `sub()' And Backslash +Table 9.2: GNU `awk' Rules For `sub()' And Backslash In a nutshell, at the runtime level, there are now three special sequences of characters (`\\\&', `\\&' and `\&') whereas historically @@ -12448,11 +12501,11 @@ there was only one. However, as in the historical case, any `\' that is not part of one of these three sequences is not special and appears in the output literally. - `gawk' 3.0 and 3.1 follow these proposed POSIX rules for `sub()' and -`gsub()'. The POSIX standard took much longer to be revised than was -expected in 1996. The 2001 standard does not follow the above rules. -Instead, the rules there are somewhat simpler. The results are similar -except for one case. + `gawk' 3.0 and 3.1 follow these rules for `sub()' and `gsub()'. The +POSIX standard took much longer to be revised than was expected. In +addition, the `gawk' maintainer's proposal was lost during the +standardization process. The final rules are somewhat simpler. The +results are similar except for one case. The POSIX rules state that `\&' in the replacement string produces a literal `&', `\\' produces a literal `\', and `\' followed by anything @@ -12461,25 +12514,25 @@ rules are presented in *note table-posix-sub::. You type `sub()' sees `sub()' generates ------- --------- -------------- - `\\\\\\&' `\\\&' a literal `\&' - `\\\\&' `\\&' a literal `\', followed by the matched text - `\\&' `\&' a literal `&' - `\\q' `\q' a literal `\q' + `\\\\\\&' `\\\&' A literal `\&' + `\\\\&' `\\&' A literal `\', followed by the matched text + `\\&' `\&' A literal `&' + `\\q' `\q' A literal `\q' `\\\\' `\\' `\' -Table 9.4: POSIX Rules For `sub()' And `gsub()' +Table 9.3: POSIX Rules For `sub()' And `gsub()' The only case where the difference is noticeable is the last one: `\\\\' is seen as `\\' and produces `\' instead of `\\'. Starting with version 3.1.4, `gawk' followed the POSIX rules when `--posix' is specified (*note Options::). Otherwise, it continued to -follow the 1996 proposed rules, since that had been its behavior for -many years. +follow the proposed rules, since that had been its behavior for many +years. When version 4.0.0 was released, the `gawk' maintainer made the POSIX rules the default, breaking well over a decade's worth of -backwards compatibility.(2) Needless to say, this was a bad idea, and +backwards compatibility.(1) Needless to say, this was a bad idea, and as of version 4.0.1, `gawk' resumed its historical behavior, and only follows the POSIX rules when `--posix' is given. @@ -12492,14 +12545,14 @@ the `\' does not, as shown in *note table-gensub-escapes::. You type `gensub()' sees `gensub()' generates ------- ------------ ----------------- - `&' `&' the matched text - `\\&' `\&' a literal `&' - `\\\\' `\\' a literal `\' - `\\\\&' `\\&' a literal `\', then the matched text - `\\\\\\&' `\\\&' a literal `\&' - `\\q' `\q' a literal `q' + `&' `&' The matched text + `\\&' `\&' A literal `&' + `\\\\' `\\' A literal `\' + `\\\\&' `\\&' A literal `\', then the matched text + `\\\\\\&' `\\\&' A literal `\&' + `\\q' `\q' A literal `q' -Table 9.5: Escape Sequence Processing For `gensub()' +Table 9.4: Escape Sequence Processing For `gensub()' Because of the complexity of the lexical and runtime level processing and the special cases for `sub()' and `gsub()', we recommend the use of @@ -12518,9 +12571,7 @@ Although this makes a certain amount of sense, it can be surprising. ---------- Footnotes ---------- - (1) This consequence was certainly unintended. - - (2) This was rather naive of him, despite there being a note in this + (1) This was rather naive of him, despite there being a note in this section indicating that the next major version would move to the POSIX rules. @@ -12567,10 +12618,10 @@ parameters are enclosed in square brackets ([ ]): function--`gawk' also buffers its output and the `fflush()' function forces `gawk' to flush its buffers. - `fflush()' was added to Brian Kernighan's `awk' in April of 1992. - For two decades, it was not part of the POSIX standard. As of - December, 2012, it was accepted for inclusion into the POSIX - standard. See the Austin Group website + `fflush()' was added to BWK `awk' in April of 1992. For two + decades, it was not part of the POSIX standard. As of December, + 2012, it was accepted for inclusion into the POSIX standard. See + the Austin Group website (http://austingroupbugs.net/view.php?id=634). POSIX standardizes `fflush()' as follows: If there is no argument, @@ -13051,7 +13102,7 @@ table-bitwise-ops::. 0 | 0 0 | 0 1 | 0 1 1 | 0 1 | 1 1 | 1 0 -Table 9.6: Bitwise Operations +Table 9.5: Bitwise Operations As you can see, the result of an AND operation is 1 only when _both_ bits are 1. The result of an OR operation is 1 if _either_ bit is 1. @@ -13249,7 +13300,10 @@ File: gawk.info, Node: Definition Syntax, Next: Function Example, Up: User-de 9.2.1 Function Definition Syntax -------------------------------- -Definitions of functions can appear anywhere between the rules of an + It's entirely fair to say that the `awk' syntax for local variable + definitions is appallingly awful. -- Brian Kernighan + + Definitions of functions can appear anywhere between the rules of an `awk' program. Thus, the general form of an `awk' program is extended to include sequences of rules _and_ user-defined function definitions. There is no need to put the definition of a function before all uses of @@ -13279,7 +13333,7 @@ have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters cannot have the same name as one of the special built-in variables (*note Built-in Variables::). Not all versions of `awk' enforce this -restriction.) +restriction. Local variables act like the empty string if referenced where a string value is required, and like zero if referenced where a numeric @@ -13386,7 +13440,8 @@ this program, using our function to format the results, prints: 5.6 21.2 - This function deletes all the elements in an array: + This function deletes all the elements in an array (recall that the +extra whitespace signifies the start of the local variable list): function delarray(a, i) { @@ -13405,22 +13460,22 @@ standard.) The following is an example of a recursive function. It takes a string as an input parameter and returns the string in backwards order. Recursive functions must always have a test that stops the recursion. -In this case, the recursion terminates when the starting position is -zero, i.e., when there are no more characters left in the string. +In this case, the recursion terminates when the input string is already +empty. - function rev(str, start) + function rev(str) { - if (start == 0) + if (str == "") return "" - return (substr(str, start, 1) rev(str, start - 1)) + return (rev(substr(str, 2)) substr(str, 1, 1)) } If this function is in a file named `rev.awk', it can be tested this way: $ echo "Don't Panic!" | - > gawk --source '{ print rev($0, length($0)) }' -f rev.awk + > gawk -e '{ print rev($0) }' -f rev.awk -| !cinaP t'noD The C `ctime()' function takes a timestamp and returns it in a @@ -13670,8 +13725,8 @@ function _are_ visible outside that function. a[1], a[2], a[3] } - prints `a[1] = 1, a[2] = two, a[3] = 3', because `changeit' stores - `"two"' in the second element of `a'. + prints `a[1] = 1, a[2] = two, a[3] = 3', because `changeit()' + stores `"two"' in the second element of `a'. Some `awk' implementations allow you to call a function that has not been defined. They only report a problem at runtime when the program @@ -13820,7 +13875,7 @@ File: gawk.info, Node: Indirect Calls, Next: Functions Summary, Prev: User-de 9.3 Indirect Function Calls =========================== -This section describes a `gawk'-specific extension. +This section describes an advanced, `gawk'-specific extension. Often, you may wish to defer the choice of function to call until runtime. For example, you may have different kinds of records, each of @@ -13859,7 +13914,7 @@ your test scores: This style of programming works, but can be awkward. With "indirect" function calls, you tell `gawk' to use the _value_ of a variable as the -name of the function to call. +_name_ of the function to call. The syntax is similar to that of a regular function call: an identifier immediately followed by a left parenthesis, any arguments, @@ -13901,7 +13956,6 @@ using indirect function calls. Otherwise they perform the expected computations and are not unusual. # For each record, print the class name and the requested statistics - { class_name = $1 gsub(/_/, " ", class_name) # Replace _ with spaces @@ -14088,11 +14142,11 @@ names of the two comparison functions: Remember that you must supply a leading `@' in front of an indirect function call. - Unfortunately, indirect function calls cannot be used with the -built-in functions. However, you can generally write "wrapper" -functions which call the built-in ones, and those can be called -indirectly. (Other than, perhaps, the mathematical functions, there is -not a lot of reason to try to call the built-in functions indirectly.) + Starting with version 4.1.2 of `gawk', indirect function calls may +also be used with built-in functions and with extension functions +(*note Dynamic Extensions::). The only thing you cannot do is pass a +regular expression constant to a built-in function through an indirect +function call.(1) `gawk' does its best to make indirect function calls efficient. For example, in the following case: @@ -14100,7 +14154,12 @@ example, in the following case: for (i = 1; i <= n; i++) @the_func() -`gawk' will look up the actual function to call only once. +`gawk' looks up the actual function to call only once. + + ---------- Footnotes ---------- + + (1) This may change in a future version; recheck the documentation +that comes with your version of `gawk' to see if it has. File: gawk.info, Node: Functions Summary, Prev: Indirect Calls, Up: Functions @@ -14137,7 +14196,9 @@ File: gawk.info, Node: Functions Summary, Prev: Indirect Calls, Up: Functions * User-defined functions may call other user-defined (and built-in) functions and may call themselves recursively. Function parameters - "hide" any global variables of the same names. + "hide" any global variables of the same names. You cannot use the + name of a reserved variable (such as `ARGC') as the name of a + parameter in user-defined functions. * Scalar values are passed to user-defined functions by value. Array parameters are passed by reference; any changes made by the @@ -14153,10 +14214,9 @@ File: gawk.info, Node: Functions Summary, Prev: Indirect Calls, Up: Functions either scalar or array. * `gawk' provides indirect function calls using a special syntax. - By setting a variable to the name of a user-defined function, you - can determine at runtime what function will be called at that - point in the program. This is equivalent to function pointers in C - and C++. + By setting a variable to the name of a function, you can determine + at runtime what function will be called at that point in the + program. This is equivalent to function pointers in C and C++. @@ -14184,7 +14244,7 @@ P.J. Plauger wrote: In fact, they felt this idea was so important that they placed this statement on the cover of their book. Because we believe strongly that their statement is correct, this major node and *note Sample -Programs::, provide a good-sized body of code for you to read, and we +Programs::, provide a good-sized body of code for you to read and, we hope, to learn from. This major node presents a library of useful `awk' functions. Many @@ -14236,7 +14296,7 @@ for different implementations of `awk' is pretty straightforward. * Group Functions:: Functions for getting group information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. ---------- Footnotes ---------- @@ -14371,8 +14431,9 @@ versions of `awk': ret = 0 for (i = 1; i <= n; i++) { c = substr(str, i, 1) - if ((k = index("01234567", c)) > 0) - k-- # adjust for 1-basing in awk + # index() returns 0 if c not in string, + # includes c == "0" + k = index("1234567", c) ret = ret * 8 + k } @@ -14384,6 +14445,8 @@ versions of `awk': for (i = 1; i <= n; i++) { c = substr(str, i, 1) c = tolower(c) + # index() returns 0 if c not in string, + # includes c == "0" k = index("123456789abcdef", c) ret = ret * 16 + k @@ -14664,8 +14727,7 @@ worrying about: } #### test code #### - # BEGIN \ - # { + # BEGIN { # for (;;) { # printf("enter a character: ") # if (getline var <= 0) @@ -15333,8 +15395,7 @@ not an option, and it ends option processing. Continuing on: i = index(options, thisopt) if (i == 0) { if (Opterr) - printf("%c -- invalid option\n", - thisopt) > "/dev/stderr" + printf("%c -- invalid option\n", thisopt) > "/dev/stderr" if (_opti >= length(argv[Optind])) { Optind++ _opti = 0 @@ -15788,8 +15849,7 @@ the same names: # group.awk --- functions for dealing with the group file - BEGIN \ - { + BEGIN { # Change to suit your system _gr_awklib = "/usr/local/libexec/awk/" } @@ -15993,7 +16053,7 @@ value. Here is a main program to demonstrate: -| a[3] = 3 -File: gawk.info, Node: Library Functions Summary, Next: Library exercises, Prev: Walking Arrays, Up: Library Functions +File: gawk.info, Node: Library Functions Summary, Next: Library Exercises, Prev: Walking Arrays, Up: Library Functions 10.8 Summary ============ @@ -16030,7 +16090,7 @@ File: gawk.info, Node: Library Functions Summary, Next: Library exercises, Pr -File: gawk.info, Node: Library exercises, Prev: Library Functions Summary, Up: Library Functions +File: gawk.info, Node: Library Exercises, Prev: Library Functions Summary, Up: Library Functions 10.9 Exercises ============== @@ -16212,8 +16272,7 @@ through the command-line options. Exactly one of the variables should be done by fields or by characters, respectively. When cutting by characters, the output field separator is set to the null string: - BEGIN \ - { + BEGIN { FS = "\t" # default OFS = FS while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) { @@ -16598,8 +16657,7 @@ line is printed, with a leading file name and colon if necessary: The `END' rule takes care of producing the correct exit status. If there are no matches, the exit status is one; otherwise it is zero: - END \ - { + END { exit (total == 0) } @@ -16617,13 +16675,6 @@ options, and then exits: The variable `e' is used so that the function fits nicely on the printed page. - Just a note on programming style: you may have noticed that the `END' -rule uses backslash continuation, with the open brace on a line by -itself. This is so that it more closely resembles the way functions -are written. Many of the examples in this major node use this style. -You can decide for yourself if you like writing your `BEGIN' and `END' -rules this way or not. - ---------- Footnotes ---------- (1) It also introduces a subtle bug; if a match happens, we output @@ -16666,8 +16717,7 @@ and the group numbers: # uid=12(foo) euid=34(bar) gid=3(baz) \ # egid=5(blat) groups=9(nine),2(two),1(one) - BEGIN \ - { + BEGIN { uid = PROCINFO["uid"] euid = PROCINFO["euid"] gid = PROCINFO["gid"] @@ -16875,8 +16925,7 @@ input by setting `ARGV[1]' to `"-"' and `ARGC' to two: # Copy standard input to all named output files. # Append content if -a option is supplied. # - BEGIN \ - { + BEGIN { for (i = 1; i < ARGC; i++) copy[i] = ARGV[i] @@ -16926,8 +16975,7 @@ N input records and M output files, the first method only executes N Finally, the `END' rule cleans up by closing all the output files: - END \ - { + END { for (i in copy) close(copy[i]) } @@ -17014,8 +17062,7 @@ standard output, `/dev/stdout': # -n skip n fields # +n skip n characters, skip fields first - BEGIN \ - { + BEGIN { count = 1 outputfile = "/dev/stdout" opts = "udc0:1:2:3:4:5:6:7:8:9:" @@ -17027,7 +17074,7 @@ standard output, `/dev/stdout': else if (c == "c") do_count++ else if (index("0123456789", c) != 0) { - # getopt requires args to options + # getopt() requires args to options # this messes us up for things like -5 if (Optarg ~ /^[[:digit:]]+$/) fcount = (c Optarg) + 0 @@ -17403,8 +17450,7 @@ Statement::), but the processing could be done with a series of # Requires getlocaltime() library function # usage: alarm time [ "message" [ count [ delay ] ] ] - BEGIN \ - { + BEGIN { # Initial argument sanity checking usage1 = "usage: alarm time ['message' [count [delay]]]" usage2 = sprintf("\t(%s) time ::= hh:mm", ARGV[1]) @@ -17618,6 +17664,10 @@ array only once, in a `BEGIN' rule. However, this assumes that the "from" and "to" lists will never change throughout the lifetime of the program. + Another obvious improvement is to enable the use of ranges, such as +`a-z', as allowed by the `tr' utility. Look at the code for `cut.awk' +(*note Cut Program::) for inspiration. + ---------- Footnotes ---------- (1) On some older systems, including Solaris, the system version of @@ -17625,8 +17675,8 @@ program. enclosed in square brackets (`[a-z]') and quoted, to prevent the shell from attempting a file name expansion. This is not a feature. - (2) This program was written before `gawk' acquired the ability to -split each character in a string into separate array elements. + (2) This program was also written before `gawk' acquired the ability +to split each character in a string into separate array elements. File: gawk.info, Node: Labels Program, Next: Word Sorting, Prev: Translate Program, Up: Miscellaneous Programs @@ -17725,8 +17775,7 @@ not have been an even multiple of 20 labels in the data: Count++ } - END \ - { + END { printpage() } @@ -18221,8 +18270,8 @@ language.(1) It works as follows: 2. For any arguments that do represent `awk' text, put the arguments into a shell variable that will be expanded. There are two cases: - a. Literal text, provided with `--source' or `--source='. This - text is just appended directly. + a. Literal text, provided with `-e' or `--source'. This text is + just appended directly. b. Source file names, provided with `-f'. We use a neat trick and append `@include FILENAME' to the shell variable's @@ -18713,14 +18762,21 @@ File: gawk.info, Node: Programs Exercises, Prev: Programs Summary, Up: Sample Program::) to accept the same arguments and perform in the same way. - 4. The `split.awk' program (*note Split Program::) uses the `chr()' - and `ord()' functions to move through the letters of the alphabet. - Modify the program to instead use only the `awk' built-in - functions, such as `index()' and `substr()'. - - 5. The `split.awk' program (*note Split Program::) assumes that + 4. The `split.awk' program (*note Split Program::) assumes that letters are contiguous in the character set, which isn't true for - EBCDIC systems. Fix this problem. + EBCDIC systems. Fix this problem. (Hint: Consider a different + way to work through the alphabet, without relying on `ord()' and + `chr()'.) + + 5. In `uniq.awk' (*note Uniq Program::, the logic for choosing which + lines to print represents a "state machine", which is "a device + that can be in one of a set number of stable conditions depending + on its previous condition and on the present values of its + inputs."(1) Brian Kernighan suggests that "an alternative approach + to state mechines is to just read the input into an array, then + use indexing. It's almost always easier code, and for most inputs + where you would use this, just as fast." Rewrite the logic to + follow this suggestion. 6. Why can't the `wc.awk' program (*note Wc Program::) just use the value of `FNR' in `endfile()'? Hint: Examine the code in *note @@ -18783,6 +18839,11 @@ File: gawk.info, Node: Programs Exercises, Prev: Programs Summary, Up: Sample of the external `sort' utility. + ---------- Footnotes ---------- + + (1) This is the definition returned from entering `define: state +machine' into Google. + File: gawk.info, Node: Advanced Features, Next: Internationalization, Prev: Sample Programs, Up: Top @@ -19221,24 +19282,7 @@ File: gawk.info, Node: Two-way I/O, Next: TCP/IP Networking, Prev: Array Sort 12.3 Two-Way Communications with Another Process ================================================ - From: brennan@whidbey.com (Mike Brennan) - Newsgroups: comp.lang.awk - Subject: Re: Learn the SECRET to Attract Women Easily - Date: 4 Aug 1997 17:34:46 GMT - Message-ID: <5s53rm$eca@news.whidbey.com> - - On 3 Aug 1997 13:17:43 GMT, Want More Dates??? - <tracy78@kilgrona.com> wrote: - >Learn the SECRET to Attract Women Easily - > - >The SCENT(tm) Pheromone Sex Attractant For Men to Attract Women - - The scent of awk programmers is a lot more attractive to women than - the scent of perl programmers. - -- - Mike Brennan - - It is often useful to be able to send data to a separate program for +It is often useful to be able to send data to a separate program for processing and then read the result. This can always be done with temporary files: @@ -19257,12 +19301,11 @@ temporary files: This works, but not elegantly. Among other things, it requires that the program be run in a directory that cannot be shared among users; for example, `/tmp' will not do, as another user might happen to be -using a temporary file with the same name. - - However, with `gawk', it is possible to open a _two-way_ pipe to -another process. The second process is termed a "coprocess", since it -runs in parallel with `gawk'. The two-way connection is created using -the `|&' operator (borrowed from the Korn shell, `ksh'):(1) +using a temporary file with the same name.(1) However, with `gawk', it +is possible to open a _two-way_ pipe to another process. The second +process is termed a "coprocess", since it runs in parallel with `gawk'. +The two-way connection is created using the `|&' operator (borrowed +from the Korn shell, `ksh'):(2) do { print DATA |& "subprogram" @@ -19349,7 +19392,11 @@ using regular pipes. ---------- Footnotes ---------- - (1) This is very different from the same operator in the C shell and + (1) Michael Brennan suggests the use of `rand()' to generate unique +file names. This is a valid point; nevertheless, temporary files remain +more difficult than two-way pipes. + + (2) This is very different from the same operator in the C shell and in Bash. @@ -19372,7 +19419,7 @@ network connection. You can think of this as just a _very long_ two-way pipeline to a coprocess. The way `gawk' decides that you want to use TCP/IP networking is by recognizing special file names that begin with one of -`/inet/', `/inet4/' or `/inet6'. +`/inet/', `/inet4/' or `/inet6/'. The full syntax of the special file name is `/NET-TYPE/PROTOCOL/LOCAL-PORT/REMOTE-HOST/REMOTE-PORT'. The @@ -19847,9 +19894,9 @@ are: `LC_CTYPE' Character-type information (alphabetic, digit, upper- or - lowercase, and so on). This information is accessed via the POSIX - character classes in regular expressions, such as `/[[:alnum:]]/' - (*note Regexp Operators::). + lowercase, and so on) as well as character encoding. This + information is accessed via the POSIX character classes in regular + expressions, such as `/[[:alnum:]]/' (*note Regexp Operators::). `LC_MONETARY' Monetary information, such as the currency symbol, and whether the @@ -19859,10 +19906,6 @@ are: Numeric information, such as which characters to use for the decimal point and the thousands separator.(2) -`LC_RESPONSE' - Response information, such as how "yes" and "no" appear in the - local language, and possibly other information as well. - `LC_TIME' Time- and date-related information, such as 12- or 24-hour clock, month printed before or after the day in a date, local month @@ -19959,16 +20002,27 @@ outlined in *note Explaining gettext::, like so: printf(_"Number of users is %d\n", nusers) 3. If you are creating strings dynamically, you can still translate - them, using the `dcgettext()' built-in function: + them, using the `dcgettext()' built-in function:(1) - message = nusers " users logged in" - message = dcgettext(message, "adminprog") - print message + if (groggy) + message = dcgettext("%d customers disturbing me\n", "adminprog") + else + message = dcgettext("enjoying %d customers\n", "adminprog") + printf(message, ncustomers) Here, the call to `dcgettext()' supplies a different text domain (`"adminprog"') in which to find the message, but it uses the default `"LC_MESSAGES"' category. + The previous example only works if `ncustomers' is greater than + one. This example would be better done with `dcngettext()': + + if (groggy) + message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") + else + message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") + printf(message, ncustomers) + 4. During development, you might want to put the `.gmo' file in a private directory for testing. This is done with the `bindtextdomain()' built-in function: @@ -19988,6 +20042,10 @@ outlined in *note Explaining gettext::, like so: *Note I18N Example::, for an example program showing the steps to create and use translations from `awk'. + ---------- Footnotes ---------- + + (1) Thanks to Bruno Haible for this example. + File: gawk.info, Node: Translator i18n, Next: I18N Example, Prev: Programmer i18n, Up: Internationalization @@ -20027,8 +20085,11 @@ Instead, it parses it as usual and prints all marked strings to standard output in the format of a GNU `gettext' Portable Object file. Also included in the output are any constant strings that appear as the first argument to `dcgettext()' or as the first and second argument to -`dcngettext()'.(1) *Note I18N Example::, for the full list of steps to -go through to create and test translations for `guide'. +`dcngettext()'.(1) You should distribute the generated `.pot' file with +your `awk' program; translators will eventually use it to provide you +translations that you can also then distribute. *Note I18N Example::, +for the full list of steps to go through to create and test +translations for `guide'. ---------- Footnotes ---------- @@ -20245,8 +20306,7 @@ file to machine-readable `.mo' file. By default, `msgfmt' creates a file named `messages'. This file must be renamed and placed in the proper directory so that `gawk' can find it: - $ msgfmt guide-mellow.po - $ mv messages en_US.UTF-8/LC_MESSAGES/guide.mo + $ msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo Finally, we run the program to test it: @@ -20500,7 +20560,7 @@ options. (`gawk' is not designed to debug command-line programs, only programs contained in files.) In our case, we invoke the debugger like this: - $ gawk -D -f getopt.awk -f join.awk -f uniq.awk inputfile + $ gawk -D -f getopt.awk -f join.awk -f uniq.awk -1 inputfile where both `getopt.awk' and `uniq.awk' are in `$AWKPATH'. (Experienced users of GDB or similar debuggers should note that this syntax is @@ -20552,7 +20612,7 @@ for a breakpoint in `uniq.awk' is at the beginning of the function To set the breakpoint, use the `b' (breakpoint) command: gawk> b are_equal - -| Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 64 + -| Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 63 The debugger tells us the file and line number where the breakpoint is. Now type `r' or `run' and the program runs until it hits the @@ -20562,8 +20622,8 @@ breakpoint for the first time: -| Starting program: -| Stopping in Rule ... -| Breakpoint 1, are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':64 - -| 64 if (fcount == 0 && charcount == 0) + at `awklib/eg/prog/uniq.awk':63 + -| 63 if (fcount == 0 && charcount == 0) gawk> Now we can look at what's going on inside our program. First of all, @@ -20573,11 +20633,11 @@ the current stack frames: gawk> bt -| #0 are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':69 - -| #1 in main() at `awklib/eg/prog/uniq.awk':89 + at `awklib/eg/prog/uniq.awk':68 + -| #1 in main() at `awklib/eg/prog/uniq.awk':88 This tells us that `are_equal()' was called by the main program at -line 89 of `uniq.awk'. (This is not a big surprise, since this is the +line 88 of `uniq.awk'. (This is not a big surprise, since this is the only call to `are_equal()' in the program, but in more complex programs, knowing who called a function and with what parameters can be the key to finding the source of the problem.) @@ -20596,13 +20656,13 @@ function was called without arguments (*note Function Calls::). A more useful variable to display might be the current record: gawk> p $0 - -| $0 = string ("gawk is a wonderful program!") + -| $0 = "gawk is a wonderful program!" This might be a bit puzzling at first since this is the second line of our test input above. Let's look at `NR': gawk> p NR - -| NR = number (2) + -| NR = 2 So we can see that `are_equal()' was only called for the second record of the file. Of course, this is because our program contains a rule for @@ -20616,7 +20676,7 @@ of the file. Of course, this is because our program contains a rule for OK, let's just check that that rule worked correctly: gawk> p last - -| last = string ("awk is a wonderful program!") + -| last = "awk is a wonderful program!" Everything we have done so far has verified that the program has worked as planned, up to and including the call to `are_equal()', so @@ -20625,38 +20685,39 @@ must begin "stepping through" the lines of `are_equal()'. We start by typing `n' (for "next"): gawk> n - -| 67 if (fcount > 0) { + -| 66 if (fcount > 0) { - This tells us that `gawk' is now ready to execute line 67, which + This tells us that `gawk' is now ready to execute line 66, which decides whether to give the lines the special "field skipping" treatment -indicated by the `-f' command-line option. (Notice that we skipped -from where we were before at line 64 to here, since the condition in -line 64 `if (fcount == 0 && charcount == 0)' was false.) +indicated by the `-1' command-line option. (Notice that we skipped +from where we were before at line 63 to here, since the condition in +line 63 `if (fcount == 0 && charcount == 0)' was false.) Continuing to step, we now get to the splitting of the current and last records: gawk> n - -| 68 n = split(last, alast) + -| 67 n = split(last, alast) gawk> n - -| 69 m = split($0, aline) + -| 68 m = split($0, aline) At this point, we should be curious to see what our records were split into, so we try to look: gawk> p n m alast aline - -| n = number (5) - -| m = number (5) + -| n = 5 + -| m = untyped variable -| alast = array, 5 elements - -| aline = array, 5 elements + -| aline = untyped variable (The `p' command can take more than one argument, similar to `awk''s `print' statement.) This is kind of disappointing, though. All we found out is that -there are five elements in each of our arrays. Useful enough (we now -know that none of the words were accidentally left out), but what if we -want to see inside the array? +there are five elements in `alast'; `m' and `aline' don't have values +yet since we are at line 68 but haven't executed it yet. This +information is useful enough (we now know that none of the words were +accidentally left out), but what if we want to see inside the array? The first choice would be to use subscripts: @@ -20666,25 +20727,25 @@ want to see inside the array? Oops! gawk> p alast[1] - -| alast["1"] = string ("awk") + -| alast["1"] = "awk" This would be kind of slow for a 100-member array, though, so `gawk' provides a shortcut (reminiscent of another language not to be mentioned): gawk> p @alast - -| alast["1"] = string ("awk") - -| alast["2"] = string ("is") - -| alast["3"] = string ("a") - -| alast["4"] = string ("wonderful") - -| alast["5"] = string ("program!") + -| alast["1"] = "awk" + -| alast["2"] = "is" + -| alast["3"] = "a" + -| alast["4"] = "wonderful" + -| alast["5"] = "program!" It looks like we got this far OK. Let's take another step or two: gawk> n - -| 70 clast = join(alast, fcount, n) + -| 69 clast = join(alast, fcount, n) gawk> n - -| 71 cline = join(aline, fcount, m) + -| 70 cline = join(aline, fcount, m) Well, here we are at our error (sorry to spoil the suspense). What we had in mind was to join the fields starting from the second one to @@ -20692,8 +20753,8 @@ make the virtual record to compare, and if the first field was numbered zero, this would work. Let's look at what we've got: gawk> p cline clast - -| cline = string ("gawk is a wonderful program!") - -| clast = string ("awk is a wonderful program!") + -| cline = "gawk is a wonderful program!" + -| clast = "awk is a wonderful program!" Hey, those look pretty familiar! They're just our original, unaltered, input records. A little thinking (the human brain is still @@ -21333,7 +21394,7 @@ some limitations. A few which are worth being aware of are: what your mistake was, though, you'll feel like a real guru. * If you perused the dump of opcodes in *note Miscellaneous Debugger - Commands::, (or if you are already familiar with `gawk' internals), + Commands:: (or if you are already familiar with `gawk' internals), you will realize that much of the internal manipulation of data in `gawk', as in many interpreters, is done on a stack. `Op_push', `Op_pop', etc., are the "bread and butter" of most `gawk' code. @@ -21377,8 +21438,8 @@ File: gawk.info, Node: Debugging Summary, Prev: Limitations, Up: Debugger * Debuggers let you step through your program one statement at a time, examine and change variable and array values, and do a - number of other things that let understand what your program is - actually doing (as opposed to what it is supposed to do). + number of other things that let you understand what your program + is actually doing (as opposed to what it is supposed to do). * Like most debuggers, the `gawk' debugger works in terms of stack frames, and lets you set both breakpoints (stop at a point in the @@ -21409,6 +21470,10 @@ in `gawk'. It continues on to present arbitrary precision integers, and concludes with a description of some points where `gawk' and the POSIX standard are not quite in agreement. + NOTE: Most users of `gawk' can safely skip this chapter. But if + you want to do scientific calculations with `gawk', this is the + place to be. + * Menu: * Computer Arithmetic:: A quick intro to computer math. @@ -21539,9 +21604,18 @@ material here. number and infinity produce infinity. "NaN" - "Not A Number." A special value indicating a result that can't - happen in real math, but that can happen in floating-point - computations. + "Not A Number."(1). A special value that results from attempting a + calculation that has no answer as a real number. In such a case, + programs can either receive a floating-point exception, or get + `NaN' back as the result. The IEEE 754 standard recommends that + systems return `NaN'. Some examples: + + `sqrt(-1)' + This makes sense in the range of complex numbers, but not in + the range of real numbers, so the result is `NaN'. + + `log(-8)' + -8 is out of the domain of `log()', so the result is `NaN'. "Normalized" How the significand (see later in this list) is usually stored. The @@ -21599,6 +21673,11 @@ Table 15.1: Basic IEEE Format Context Values NOTE: The precision numbers include the implied leading one that gives them one extra bit of significand. + ---------- Footnotes ---------- + + (1) Thanks to Michael Brennan for this description, which I have +paraphrased, and for the examples + File: gawk.info, Node: MPFR features, Next: FP Math Caution, Prev: Math Definitions, Up: Arbitrary Precision Arithmetic @@ -21627,10 +21706,9 @@ Auto-set::). The MPFR library provides precise control over precisions and rounding modes, and gives correctly rounded, reproducible, -platform-independent results. With either of the command-line options -`--bignum' or `-M', all floating-point arithmetic operators and numeric -functions can yield results to any desired precision level supported by -MPFR. +platform-independent results. With the `-M' command-line option, all +floating-point arithmetic operators and numeric functions can yield +results to any desired precision level supported by MPFR. Two built-in variables, `PREC' and `ROUNDMODE', provide control over the working precision and the rounding mode. The precision and the @@ -21643,7 +21721,7 @@ File: gawk.info, Node: FP Math Caution, Next: Arbitrary Precision Integers, P 15.4 Floating Point Arithmetic: Caveat Emptor! ============================================== - Math class is tough! -- Late 1980's Barbie + Math class is tough! -- Teen Talk Barbie, July 1992 This minor node provides a high level overview of the issues involved when doing lots of floating-point arithmetic.(1) The @@ -21926,7 +22004,7 @@ on arithmetic operations: of a constant. If you need to represent a floating-point constant at a higher - precision than the default and cannot use a command line + precision than the default and cannot use a command-line assignment to `PREC', you should either specify the constant as a string, or as a rational number, whenever possible. The following example illustrates the differences among various ways to print a @@ -22037,13 +22115,13 @@ File: gawk.info, Node: Arbitrary Precision Integers, Next: POSIX Floating Poin 15.5 Arbitrary Precision Integer Arithmetic with `gawk' ======================================================= -When given one of the options `--bignum' or `-M', `gawk' performs all -integer arithmetic using GMP arbitrary precision integers. Any number -that looks like an integer in a source or data file is stored as an -arbitrary precision integer. The size of the integer is limited only -by the available memory. For example, the following computes 5^4^3^2, -the result of which is beyond the limits of ordinary hardware -double-precision floating point values: +When given the `-M' option, `gawk' performs all integer arithmetic +using GMP arbitrary precision integers. Any number that looks like an +integer in a source or data file is stored as an arbitrary precision +integer. The size of the integer is limited only by the available +memory. For example, the following computes 5^4^3^2, the result of +which is beyond the limits of ordinary hardware double-precision +floating point values: $ gawk -M 'BEGIN { > x = 5^4^3^2 @@ -22228,7 +22306,7 @@ File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Prob floating-point values. The default for `awk' is to use double-precision floating-point values. - * In the 1980's, Barbie mistakenly said "Math class is tough!" + * In the early 1990's, Barbie mistakenly said "Math class is tough!" While math isn't tough, floating-point arithmetic isn't the same as pencil and paper math, and care must be taken: @@ -22246,13 +22324,13 @@ File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Prob * Often, increasing the accuracy and then rounding to the desired number of digits produces reasonable results. - * Use either `-M' or `--bignum' to enable MPFR arithmetic. Use - `PREC' to set the precision in bits, and `ROUNDMODE' to set the - IEEE 754 rounding mode. + * Use `-M' (or `--bignum') to enable MPFR arithmetic. Use `PREC' to + set the precision in bits, and `ROUNDMODE' to set the IEEE 754 + rounding mode. - * With `-M' or `--bignum', `gawk' performs arbitrary precision - integer arithmetic using the GMP library. This is faster and more - space efficient than using MPFR for the same calculations. + * With `-M', `gawk' performs arbitrary precision integer arithmetic + using the GMP library. This is faster and more space efficient + than using MPFR for the same calculations. * There are several "dark corners" with respect to floating-point numbers where `gawk' disagrees with the POSIX standard. It pays @@ -22444,7 +22522,7 @@ Example::) and also the `testext.c' code for testing the APIs. Some other bits and pieces: * The API provides access to `gawk''s `do_XXX' values, reflecting - command line options, like `do_lint', `do_profiling' and so on + command-line options, like `do_lint', `do_profiling' and so on (*note Extension API Variables::). These are informational: an extension cannot affect their values inside `gawk'. In addition, attempting to assign to them produces a compile-time error. @@ -22572,7 +22650,7 @@ operations: place `-Dinline=''' on your command line, or use the GNU Autotools and include a `config.h' file in your extensions. - * All pointers filled in by `gawk' are to memory managed by `gawk' + * All pointers filled in by `gawk' point to memory managed by `gawk' and should be treated by the extension as read-only. Memory for _all_ strings passed into `gawk' from the extension _must_ come from calling the API-provided function pointers `api_malloc()', @@ -22982,7 +23060,7 @@ File: gawk.info, Node: Exit Callback Functions, Next: Extension Version String An "exit callback" function is a function that `gawk' calls before it exits. Such functions are useful if you have general "cleanup" tasks -that should be performed in your extension (such as closing data base +that should be performed in your extension (such as closing database connections or other resource deallocations). You can register such a function with `gawk' using the following function. @@ -26038,7 +26116,7 @@ the current version of `gawk'. - Indirect function calls (*note Indirect Calls::). - Directories on the command line produce a warning and are - skipped (*note Command line directories::). + skipped (*note Command-line directories::). * New keywords: @@ -26087,8 +26165,8 @@ the current version of `gawk'. - The `bindtextdomain()', `dcgettext()' and `dcngettext()' functions for internationalization (*note Programmer i18n::). - - The `fflush()' function from Brian Kernighan's version of - `awk' (*note I/O Functions::). + - The `fflush()' function from BWK `awk' (*note I/O + Functions::). - The `gensub()', `patsplit()', and `strtonum()' functions for more powerful text manipulation (*note String Functions::). @@ -26109,7 +26187,7 @@ the current version of `gawk'. `-r', `-S', `-t', and `-V' short options. Also, the ability to use GNU-style long-named options that start with `--' and the `--assign', `--bignum', `--characters-as-bytes', - `--copyright', `--debug', `--dump-variables', `--execle', + `--copyright', `--debug', `--dump-variables', `--exec', `--field-separator', `--file', `--gen-pot', `--help', `--include', `--lint', `--lint-old', `--load', `--non-decimal-data', `--optimize', `--posix', @@ -26150,6 +26228,8 @@ the current version of `gawk'. - Ultrix + * Support for MirBSD was removed at `gawk' version 4.2. + File: gawk.info, Node: Feature History, Next: Common Extensions, Prev: POSIX/GNU, Up: Language History @@ -26208,7 +26288,7 @@ in POSIX `awk', in the order they were added to `gawk'. * The ability to delete all of an array at once with `delete ARRAY' (*note Delete::). - * Command line option changes (*note Options::): + * Command-line option changes (*note Options::): - The ability to use GNU-style long-named options that start with `--'. @@ -26242,18 +26322,18 @@ in POSIX `awk', in the order they were added to `gawk'. * The `next file' statement became `nextfile' (*note Nextfile Statement::). - * The `fflush()' function from Brian Kernighan's `awk' (then at Bell - Laboratories; *note I/O Functions::). + * The `fflush()' function from BWK `awk' (then at Bell Laboratories; + *note I/O Functions::). - * New command line options: + * New command-line options: - The `--lint-old' option to warn about constructs that are not available in the original Version 7 Unix version of `awk' (*note V7/SVR3.1::). - - The `-m' option from Brian Kernighan's `awk'. (He was still - at Bell Laboratories at the time.) This was later removed - from both his `awk' and from `gawk'. + - The `-m' option from BWK `awk'. (Brian was still at Bell + Laboratories at the time.) This was later removed from both + his `awk' and from `gawk'. - The `--re-interval' option to provide interval expressions in regexps (*note Regexp Operators::). @@ -26413,9 +26493,9 @@ in POSIX `awk', in the order they were added to `gawk'. * An optional third argument to `asort()' and `asorti()', specifying how to sort (*note String Functions::). - * The behavior of `fflush()' changed to match Brian Kernighan's `awk' - and for POSIX; now both `fflush()' and `fflush("")' flush all open - output redirections (*note I/O Functions::). + * The behavior of `fflush()' changed to match BWK `awk' and for + POSIX; now both `fflush()' and `fflush("")' flush all open output + redirections (*note I/O Functions::). * The `isarray()' function which distinguishes if an item is an array or not, to make it possible to traverse arrays of arrays (*note @@ -26438,7 +26518,7 @@ in POSIX `awk', in the order they were added to `gawk'. * `switch' / `case' are enabled by default (*note Switch Statement::). - * Command line option changes (*note Options::): + * Command-line option changes (*note Options::): - The `-b' and `--characters-as-bytes' options which prevent `gawk' from treating input as a multibyte string. @@ -26456,7 +26536,7 @@ in POSIX `awk', in the order they were added to `gawk'. * Directories named on the command line now produce a warning, not a fatal error, unless `--posix' or `--traditional' are used (*note - Command line directories::). + Command-line directories::). * The `gawk' internals were rewritten, bringing the `dgawk' debugger and possibly improved performance (*note Debugger::). @@ -26505,10 +26585,10 @@ in POSIX `awk', in the order they were added to `gawk'. `PROCINFO["identifiers"]' (*note Auto-set::). * The three executables `gawk', `pgawk', and `dgawk', were merged - into one, named just `gawk'. As a result the command line options + into one, named just `gawk'. As a result the command-line options changed. - * Command line option changes (*note Options::): + * Command-line option changes (*note Options::): - The `-D' option invokes the debugger. @@ -27556,7 +27636,7 @@ These give the same result as the `-W BINMODE=2' option in `mawk'. The following changes the record separator to `"\r\n"' and sets binary mode on reads, but does not affect the mode on standard input: - gawk -v RS="\r\n" --source "BEGIN { BINMODE = 1 }" ... + gawk -v RS="\r\n" -e "BEGIN { BINMODE = 1 }" ... or: @@ -28024,11 +28104,11 @@ Unix `awk' since approximately 2003. `pawk' - Nelson H.F. Beebe at the University of Utah has modified Brian - Kernighan's `awk' to provide timing and profiling information. It - is different from `gawk' with the `--profile' option. (*note - Profiling::), in that it uses CPU-based profiling, not line-count - profiling. You may find it at either + Nelson H.F. Beebe at the University of Utah has modified BWK `awk' + to provide timing and profiling information. It is different from + `gawk' with the `--profile' option. (*note Profiling::), in that + it uses CPU-based profiling, not line-count profiling. You may + find it at either `ftp://ftp.math.utah.edu/pub/pawk/pawk-20030606.tar.gz' or `http://www.math.utah.edu/pub/pawk/pawk-20030606.tar.gz'. @@ -28073,7 +28153,7 @@ Libmawk This is a Python module that claims to bring `awk'-like features to Python. See `https://github.com/alecthomas/pawk' for more information. (This is not related to Nelson Beebe's modified - version of Brian Kernighan's `awk', described earlier.) + version of BWK `awk', described earlier.) QSE Awk This is an embeddable `awk' interpreter. For more information see @@ -28895,7 +28975,7 @@ C.7 Summary `--parsedebug' option is available if `gawk' is compiled with `-DDEBUG'. - * The source code for `gawk' is maintained in a publicly accessable + * The source code for `gawk' is maintained in a publicly accessible Git repository. Anyone may check it out and view the source. * Contributions to `gawk' are welcome. Following the steps outlined @@ -30956,10 +31036,9 @@ Index * ! (exclamation point), !~ operator <3>: Comparison Operators. (line 11) * ! (exclamation point), !~ operator <4>: Regexp Constants. (line 6) -* ! (exclamation point), !~ operator <5>: Computed Regexps. (line 6) -* ! (exclamation point), !~ operator <6>: Case-sensitivity. (line 26) +* ! (exclamation point), !~ operator <5>: Case-sensitivity. (line 26) +* ! (exclamation point), !~ operator <6>: Computed Regexps. (line 6) * ! (exclamation point), !~ operator: Regexp Usage. (line 19) -* " (double quote) in shell commands: Read Terminal. (line 25) * " (double quote), in regexp constants: Computed Regexps. (line 29) * " (double quote), in shell commands: Quoting. (line 54) * # (number sign), #! (executable scripts): Executable Scripts. @@ -30983,13 +31062,13 @@ Index * ' (single quote), vs. apostrophe: Comments. (line 27) * ' (single quote), with double quotes: Quoting. (line 70) * () (parentheses), in a profile: Profiling. (line 146) -* () (parentheses), regexp operator: Regexp Operators. (line 80) +* () (parentheses), regexp operator: Regexp Operators. (line 81) * * (asterisk), * operator, as multiplication operator: Precedence. (line 55) * * (asterisk), * operator, as regexp operator: Regexp Operators. - (line 88) + (line 89) * * (asterisk), * operator, null strings, matching: Gory Details. - (line 164) + (line 143) * * (asterisk), ** operator <1>: Precedence. (line 49) * * (asterisk), ** operator: Arithmetic Ops. (line 81) * * (asterisk), **= operator <1>: Precedence. (line 95) @@ -31001,7 +31080,7 @@ Index * + (plus sign), ++ operator: Increment Ops. (line 11) * + (plus sign), += operator <1>: Precedence. (line 95) * + (plus sign), += operator: Assignment Ops. (line 82) -* + (plus sign), regexp operator: Regexp Operators. (line 103) +* + (plus sign), regexp operator: Regexp Operators. (line 105) * , (comma), in range patterns: Ranges. (line 6) * - (hyphen), - operator: Precedence. (line 52) * - (hyphen), -- operator <1>: Precedence. (line 46) @@ -31064,13 +31143,14 @@ Index * -c option: Options. (line 81) * -D option: Options. (line 108) * -d option: Options. (line 93) +* -e option: Options. (line 333) * -E option: Options. (line 125) * -e option: Options. (line 117) * -f option: Options. (line 25) * -F option: Options. (line 21) * -f option: Long. (line 12) * -F option, -Ft sets FS to TAB: Options. (line 306) -* -F option, command line: Command Line Field Separator. +* -F option, command-line: Command Line Field Separator. (line 6) * -f option, multiple uses: Options. (line 311) * -g option: Options. (line 147) @@ -31143,14 +31223,17 @@ Index * ? (question mark), ?: operator: Precedence. (line 92) * ? (question mark), regexp operator <1>: GNU Regexp Operators. (line 59) -* ? (question mark), regexp operator: Regexp Operators. (line 112) +* ? (question mark), regexp operator: Regexp Operators. (line 111) +* @-notation for indirect function calls: Indirect Calls. (line 47) +* @include directive: Include Files. (line 8) +* @load directive: Loading Shared Libraries. + (line 8) * [] (square brackets), regexp operator: Regexp Operators. (line 56) * \ (backslash): Comments. (line 50) -* \ (backslash) in shell commands: Read Terminal. (line 25) -* \ (backslash), \" escape sequence: Escape Sequences. (line 76) +* \ (backslash), \" escape sequence: Escape Sequences. (line 84) * \ (backslash), \' operator (gawk): GNU Regexp Operators. (line 56) -* \ (backslash), \/ escape sequence: Escape Sequences. (line 69) +* \ (backslash), \/ escape sequence: Escape Sequences. (line 75) * \ (backslash), \< operator (gawk): GNU Regexp Operators. (line 30) * \ (backslash), \> operator (gawk): GNU Regexp Operators. @@ -31180,7 +31263,6 @@ Index (line 38) * \ (backslash), as field separator: Command Line Field Separator. (line 27) -* \ (backslash), continuing lines and <1>: Egrep Program. (line 223) * \ (backslash), continuing lines and: Statements/Lines. (line 19) * \ (backslash), continuing lines and, comments and: Statements/Lines. (line 76) @@ -31191,7 +31273,7 @@ Index * \ (backslash), in bracket expressions: Bracket Expressions. (line 17) * \ (backslash), in escape sequences: Escape Sequences. (line 6) * \ (backslash), in escape sequences, POSIX and: Escape Sequences. - (line 112) + (line 120) * \ (backslash), in regexp constants: Computed Regexps. (line 29) * \ (backslash), in shell commands: Quoting. (line 48) * \ (backslash), regexp operator: Regexp Operators. (line 18) @@ -31228,7 +31310,7 @@ Index * advanced features, network programming: TCP/IP Networking. (line 6) * advanced features, nondecimal input data: Nondecimal Data. (line 6) * advanced features, processes, communicating with: Two-way I/O. - (line 23) + (line 6) * advanced features, specifying field content: Splitting By Content. (line 10) * Aho, Alfred <1>: Contributors. (line 11) @@ -31238,7 +31320,6 @@ Index * algorithms: Basic High Level. (line 68) * allocating memory for extensions: Memory Allocation Functions. (line 6) -* Alpha (DEC): Manual History. (line 28) * amazing awk assembler (aaa): Glossary. (line 11) * amazingly workable formatter (awf): Glossary. (line 24) * ambiguity, syntactic: /= operator vs. /=.../ regexp constant: Assignment Ops. @@ -31267,7 +31348,7 @@ Index * ARGC/ARGV variables, command-line arguments: Other Arguments. (line 12) * ARGC/ARGV variables, how to use: ARGC and ARGV. (line 6) -* ARGC/ARGV variables, portability and: Executable Scripts. (line 42) +* ARGC/ARGV variables, portability and: Executable Scripts. (line 59) * ARGIND variable: Auto-set. (line 44) * ARGIND variable, command-line arguments: Other Arguments. (line 12) * arguments, command-line <1>: ARGC and ARGV. (line 6) @@ -31287,7 +31368,7 @@ Index * arrays: Arrays. (line 6) * arrays of arrays: Arrays of Arrays. (line 6) * arrays, an example of using: Array Example. (line 6) -* arrays, and IGNORECASE variable: Array Intro. (line 92) +* arrays, and IGNORECASE variable: Array Intro. (line 94) * arrays, as parameters to functions: Pass By Value/Reference. (line 47) * arrays, associative: Array Intro. (line 50) @@ -31315,7 +31396,7 @@ Index (line 6) * arrays, sorting, and IGNORECASE variable: Array Sorting Functions. (line 83) -* arrays, sparse: Array Intro. (line 71) +* arrays, sparse: Array Intro. (line 72) * arrays, subscripts, uninitialized variables as: Uninitialized Subscripts. (line 6) * arrays, unassigned elements: Reference to Elements. @@ -31347,9 +31428,9 @@ Index * asterisk (*), * operator, as multiplication operator: Precedence. (line 55) * asterisk (*), * operator, as regexp operator: Regexp Operators. - (line 88) + (line 89) * asterisk (*), * operator, null strings, matching: Gory Details. - (line 164) + (line 143) * asterisk (*), ** operator <1>: Precedence. (line 49) * asterisk (*), ** operator: Arithmetic Ops. (line 81) * asterisk (*), **= operator <1>: Precedence. (line 95) @@ -31365,7 +31446,7 @@ Index * awk programs <1>: Two Rules. (line 6) * awk programs <2>: Executable Scripts. (line 6) * awk programs: Getting Started. (line 12) -* awk programs, complex: When. (line 29) +* awk programs, complex: When. (line 27) * awk programs, documenting <1>: Library Names. (line 6) * awk programs, documenting: Comments. (line 6) * awk programs, examples of: Sample Programs. (line 6) @@ -31385,7 +31466,7 @@ Index (line 6) * awk, function of: Getting Started. (line 6) * awk, gawk and <1>: This Manual. (line 14) -* awk, gawk and: Preface. (line 23) +* awk, gawk and: Preface. (line 21) * awk, history of: History. (line 17) * awk, implementation issues, pipes: Redirection. (line 135) * awk, implementations: Other Versions. (line 6) @@ -31393,17 +31474,16 @@ Index * awk, invoking: Command Line. (line 6) * awk, new vs. old: Names. (line 6) * awk, new vs. old, OFMT variable: Strings And Numbers. (line 57) -* awk, POSIX and: Preface. (line 23) -* awk, POSIX and, See Also POSIX awk: Preface. (line 23) +* awk, POSIX and: Preface. (line 21) +* awk, POSIX and, See Also POSIX awk: Preface. (line 21) * awk, regexp constants and: Comparison Operators. (line 102) -* awk, See Also gawk: Preface. (line 36) +* awk, See Also gawk: Preface. (line 34) * awk, terms describing: This Manual. (line 6) * awk, uses for <1>: When. (line 6) * awk, uses for <2>: Getting Started. (line 12) -* awk, uses for: Preface. (line 23) -* awk, versions of <1>: V7/SVR3.1. (line 6) -* awk, versions of: Names. (line 10) +* awk, uses for: Preface. (line 21) +* awk, versions of: V7/SVR3.1. (line 6) * awk, versions of, changes between SVR3.1 and SVR4: SVR4. (line 6) * awk, versions of, changes between SVR4 and POSIX awk: POSIX. (line 6) @@ -31420,11 +31500,10 @@ Index * awkvars.out file: Options. (line 93) * b debugger command (alias for break): Breakpoint Control. (line 11) * backslash (\): Comments. (line 50) -* backslash (\) in shell commands: Read Terminal. (line 25) -* backslash (\), \" escape sequence: Escape Sequences. (line 76) +* backslash (\), \" escape sequence: Escape Sequences. (line 84) * backslash (\), \' operator (gawk): GNU Regexp Operators. (line 56) -* backslash (\), \/ escape sequence: Escape Sequences. (line 69) +* backslash (\), \/ escape sequence: Escape Sequences. (line 75) * backslash (\), \< operator (gawk): GNU Regexp Operators. (line 30) * backslash (\), \> operator (gawk): GNU Regexp Operators. @@ -31454,7 +31533,6 @@ Index (line 38) * backslash (\), as field separator: Command Line Field Separator. (line 27) -* backslash (\), continuing lines and <1>: Egrep Program. (line 223) * backslash (\), continuing lines and: Statements/Lines. (line 19) * backslash (\), continuing lines and, comments and: Statements/Lines. (line 76) @@ -31465,7 +31543,7 @@ Index * backslash (\), in bracket expressions: Bracket Expressions. (line 17) * backslash (\), in escape sequences: Escape Sequences. (line 6) * backslash (\), in escape sequences, POSIX and: Escape Sequences. - (line 112) + (line 120) * backslash (\), in regexp constants: Computed Regexps. (line 29) * backslash (\), in shell commands: Quoting. (line 48) * backslash (\), regexp operator: Regexp Operators. (line 18) @@ -31485,7 +31563,7 @@ Index * BEGIN pattern, next/nextfile statements and <1>: Next Statement. (line 45) * BEGIN pattern, next/nextfile statements and: I/O And BEGIN/END. - (line 37) + (line 36) * BEGIN pattern, OFS/ORS variables, assigning values to: Output Separators. (line 20) * BEGIN pattern, operators and: Using BEGIN/END. (line 17) @@ -31530,15 +31608,15 @@ Index * bracket expressions <1>: Bracket Expressions. (line 6) * bracket expressions: Regexp Operators. (line 56) * bracket expressions, character classes: Bracket Expressions. - (line 30) + (line 32) * bracket expressions, collating elements: Bracket Expressions. - (line 77) + (line 79) * bracket expressions, collating symbols: Bracket Expressions. - (line 84) + (line 86) * bracket expressions, complemented: Regexp Operators. (line 64) * bracket expressions, equivalence classes: Bracket Expressions. - (line 90) -* bracket expressions, non-ASCII: Bracket Expressions. (line 77) + (line 92) +* bracket expressions, non-ASCII: Bracket Expressions. (line 79) * bracket expressions, range expressions: Bracket Expressions. (line 6) * break debugger command: Breakpoint Control. (line 11) @@ -31552,16 +31630,16 @@ Index * breakpoint, how to disable or enable: Breakpoint Control. (line 69) * breakpoint, setting: Breakpoint Control. (line 11) * Brennan, Michael <1>: Other Versions. (line 6) -* Brennan, Michael <2>: Two-way I/O. (line 6) -* Brennan, Michael <3>: Simple Sed. (line 25) -* Brennan, Michael <4>: Delete. (line 56) +* Brennan, Michael <2>: Simple Sed. (line 25) +* Brennan, Michael <3>: Delete. (line 56) +* Brennan, Michael <4>: Acknowledgments. (line 76) * Brennan, Michael: Foreword. (line 83) * Brian Kernighan's awk <1>: I/O Functions. (line 43) -* Brian Kernighan's awk <2>: Gory Details. (line 15) +* Brian Kernighan's awk <2>: Gory Details. (line 19) * Brian Kernighan's awk <3>: String Functions. (line 490) * Brian Kernighan's awk <4>: Delete. (line 48) * Brian Kernighan's awk <5>: Nextfile Statement. (line 47) -* Brian Kernighan's awk <6>: Continue Statement. (line 43) +* Brian Kernighan's awk <6>: Continue Statement. (line 44) * Brian Kernighan's awk <7>: Break Statement. (line 51) * Brian Kernighan's awk <8>: I/O And BEGIN/END. (line 16) * Brian Kernighan's awk <9>: Concatenation. (line 36) @@ -31570,9 +31648,8 @@ Index (line 67) * Brian Kernighan's awk <12>: GNU Regexp Operators. (line 83) -* Brian Kernighan's awk <13>: Escape Sequences. (line 116) -* Brian Kernighan's awk <14>: When. (line 21) -* Brian Kernighan's awk: Preface. (line 15) +* Brian Kernighan's awk <13>: Escape Sequences. (line 124) +* Brian Kernighan's awk: When. (line 21) * Brian Kernighan's awk, extensions: BTL. (line 6) * Brian Kernighan's awk, source code: Other Versions. (line 13) * Brini, Davide: Signature Program. (line 6) @@ -31584,7 +31661,7 @@ Index * Buening, Andreas <1>: Bugs. (line 71) * Buening, Andreas <2>: Contributors. (line 92) * Buening, Andreas: Acknowledgments. (line 60) -* buffering, input/output <1>: Two-way I/O. (line 70) +* buffering, input/output <1>: Two-way I/O. (line 52) * buffering, input/output: I/O Functions. (line 140) * buffering, interactive vs. noninteractive: I/O Functions. (line 109) * buffers, flushing: I/O Functions. (line 32) @@ -31599,6 +31676,7 @@ Index * built-in variables, conveying information: Auto-set. (line 6) * built-in variables, user-modifiable: User-modified. (line 6) * Busybox Awk: Other Versions. (line 88) +* c.e., See common extensions: Conventions. (line 51) * call by reference: Pass By Value/Reference. (line 47) * call by value: Pass By Value/Reference. @@ -31614,7 +31692,7 @@ Index * case keyword: Switch Statement. (line 6) * case sensitivity, and regexps: User-modified. (line 76) * case sensitivity, and string comparisons: User-modified. (line 76) -* case sensitivity, array indices and: Array Intro. (line 92) +* case sensitivity, array indices and: Array Intro. (line 94) * case sensitivity, converting case: String Functions. (line 520) * case sensitivity, example programs: Library Functions. (line 53) * case sensitivity, gawk: Case-sensitivity. (line 26) @@ -31652,12 +31730,12 @@ Index (line 81) * close() function, return value: Close Files And Pipes. (line 131) -* close() function, two-way pipes and: Two-way I/O. (line 77) +* close() function, two-way pipes and: Two-way I/O. (line 59) * Close, Diane <1>: Contributors. (line 20) -* Close, Diane: Manual History. (line 41) +* Close, Diane: Manual History. (line 34) * Collado, Manuel: Acknowledgments. (line 60) -* collating elements: Bracket Expressions. (line 77) -* collating symbols: Bracket Expressions. (line 84) +* collating elements: Bracket Expressions. (line 79) +* collating symbols: Bracket Expressions. (line 86) * Colombo, Antonio <1>: Contributors. (line 137) * Colombo, Antonio: Acknowledgments. (line 60) * columns, aligning: Print Examples. (line 70) @@ -31667,7 +31745,7 @@ Index * command line, arguments <1>: ARGC and ARGV. (line 6) * command line, arguments <2>: Auto-set. (line 15) * command line, arguments: Other Arguments. (line 6) -* command line, directories on: Command line directories. +* command line, directories on: Command-line directories. (line 6) * command line, formats: Running gawk. (line 12) * command line, FS on, setting: Command Line Field Separator. @@ -31693,7 +31771,7 @@ Index * common extensions, \x escape sequence: Escape Sequences. (line 61) * common extensions, BINMODE variable: PC Using. (line 33) * common extensions, delete to delete entire arrays: Delete. (line 39) -* common extensions, func keyword: Definition Syntax. (line 89) +* common extensions, func keyword: Definition Syntax. (line 92) * common extensions, length() applied to an array: String Functions. (line 197) * common extensions, RS as a regexp: gawk split records. (line 6) @@ -31759,7 +31837,7 @@ Index * CONVFMT variable, and array subscripts: Numeric Array Subscripts. (line 6) * cookie: Glossary. (line 149) -* coprocesses <1>: Two-way I/O. (line 44) +* coprocesses <1>: Two-way I/O. (line 25) * coprocesses: Redirection. (line 102) * coprocesses, closing: Close Files And Pipes. (line 6) @@ -31768,9 +31846,9 @@ Index * cosine: Numeric Functions. (line 15) * counting: Wc Program. (line 6) * csh utility: Statements/Lines. (line 44) -* csh utility, POSIXLY_CORRECT environment variable: Options. (line 353) -* csh utility, |& operator, comparison with: Two-way I/O. (line 44) -* ctime() user-defined function: Function Example. (line 73) +* csh utility, POSIXLY_CORRECT environment variable: Options. (line 351) +* csh utility, |& operator, comparison with: Two-way I/O. (line 25) +* ctime() user-defined function: Function Example. (line 74) * currency symbols, localization: Explaining gettext. (line 104) * current system time: Time Functions. (line 66) * custom.h file: Configuration Philosophy. @@ -31781,9 +31859,9 @@ Index * cut utility: Cut Program. (line 6) * cut.awk program: Cut Program. (line 45) * d debugger command (alias for delete): Breakpoint Control. (line 64) -* d.c., See dark corner: Conventions. (line 38) +* d.c., See dark corner: Conventions. (line 42) * dark corner <1>: Glossary. (line 188) -* dark corner: Conventions. (line 38) +* dark corner: Conventions. (line 42) * dark corner, "0" is actually true: Truth Values. (line 24) * dark corner, /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) @@ -31795,17 +31873,17 @@ Index * dark corner, close() function: Close Files And Pipes. (line 131) * dark corner, command-line arguments: Assignment Options. (line 43) -* dark corner, continue statement: Continue Statement. (line 43) +* dark corner, continue statement: Continue Statement. (line 44) * dark corner, CONVFMT variable: Strings And Numbers. (line 40) -* dark corner, escape sequences: Other Arguments. (line 31) +* dark corner, escape sequences: Other Arguments. (line 35) * dark corner, escape sequences, for metacharacters: Escape Sequences. - (line 134) + (line 142) * dark corner, exit statement: Exit Statement. (line 30) * dark corner, field separators: Field Splitting Summary. (line 46) * dark corner, FILENAME variable <1>: Auto-set. (line 98) * dark corner, FILENAME variable: Getline Notes. (line 19) -* dark corner, FNR/NR variables: Auto-set. (line 309) +* dark corner, FNR/NR variables: Auto-set. (line 313) * dark corner, format-control characters: Control Letters. (line 18) * dark corner, FS as null string: Single Character Fields. (line 20) @@ -31834,9 +31912,10 @@ Index * date utility, POSIX: Time Functions. (line 254) * dates, converting to timestamps: Time Functions. (line 76) * dates, information related to, localization: Explaining gettext. - (line 116) + (line 112) * Davies, Stephen <1>: Contributors. (line 74) * Davies, Stephen: Acknowledgments. (line 60) +* Day, Robert P.J.: Acknowledgments. (line 76) * dcgettext <1>: Programmer i18n. (line 19) * dcgettext: I18N Functions. (line 22) * dcgettext() function (gawk), portability and: I18N Portability. @@ -31845,7 +31924,7 @@ Index * dcngettext: I18N Functions. (line 28) * dcngettext() function (gawk), portability and: I18N Portability. (line 33) -* deadlocks: Two-way I/O. (line 70) +* deadlocks: Two-way I/O. (line 52) * debugger commands, b (break): Breakpoint Control. (line 11) * debugger commands, backtrace: Execution Stack. (line 13) * debugger commands, break: Breakpoint Control. (line 11) @@ -31970,7 +32049,7 @@ Index * describe call stack frame, in debugger: Debugger Info. (line 27) * differences between gawk and awk: String Functions. (line 197) * differences in awk and gawk, ARGC/ARGV variables: ARGC and ARGV. - (line 88) + (line 90) * differences in awk and gawk, ARGIND variable: Auto-set. (line 44) * differences in awk and gawk, array elements, deleting: Delete. (line 39) @@ -31988,7 +32067,7 @@ Index (line 15) * differences in awk and gawk, close() function: Close Files And Pipes. (line 81) -* differences in awk and gawk, command line directories: Command line directories. +* differences in awk and gawk, command-line directories: Command-line directories. (line 6) * differences in awk and gawk, ERRNO variable: Auto-set. (line 82) * differences in awk and gawk, error messages: Special FD. (line 16) @@ -32018,7 +32097,7 @@ Index (line 260) * differences in awk and gawk, print/printf statements: Format Modifiers. (line 13) -* differences in awk and gawk, PROCINFO array: Auto-set. (line 136) +* differences in awk and gawk, PROCINFO array: Auto-set. (line 137) * differences in awk and gawk, read timeouts: Read Timeout. (line 6) * differences in awk and gawk, record separators: awk split records. (line 124) @@ -32028,7 +32107,7 @@ Index (line 26) * differences in awk and gawk, RS/RT variables: gawk split records. (line 58) -* differences in awk and gawk, RT variable: Auto-set. (line 265) +* differences in awk and gawk, RT variable: Auto-set. (line 269) * differences in awk and gawk, single-character fields: Single Character Fields. (line 6) * differences in awk and gawk, split() function: String Functions. @@ -32036,14 +32115,14 @@ Index * differences in awk and gawk, strings: Scalar Constants. (line 20) * differences in awk and gawk, strings, storing: gawk split records. (line 77) -* differences in awk and gawk, SYMTAB variable: Auto-set. (line 269) +* differences in awk and gawk, SYMTAB variable: Auto-set. (line 273) * differences in awk and gawk, TEXTDOMAIN variable: User-modified. (line 152) * differences in awk and gawk, trunc-mod operation: Arithmetic Ops. (line 66) -* directories, command line: Command line directories. +* directories, command-line: Command-line directories. (line 6) -* directories, searching: Programs Exercises. (line 63) +* directories, searching: Programs Exercises. (line 70) * directories, searching for loadable extensions: AWKLIBPATH Variable. (line 6) * directories, searching for source files: AWKPATH Variable. (line 6) @@ -32064,7 +32143,6 @@ Index * dollar sign ($), incrementing fields and arrays: Increment Ops. (line 30) * dollar sign ($), regexp operator: Regexp Operators. (line 35) -* double quote (") in shell commands: Read Terminal. (line 25) * double quote ("), in regexp constants: Computed Regexps. (line 29) * double quote ("), in shell commands: Quoting. (line 54) * down debugger command: Execution Stack. (line 21) @@ -32077,10 +32155,10 @@ Index * dynamically loaded extensions: Dynamic Extensions. (line 6) * e debugger command (alias for enable): Breakpoint Control. (line 73) * EBCDIC: Ordinal Functions. (line 45) -* effective group ID of gawk user: Auto-set. (line 141) -* effective user ID of gawk user: Auto-set. (line 145) +* effective group ID of gawk user: Auto-set. (line 142) +* effective user ID of gawk user: Auto-set. (line 146) * egrep utility <1>: Egrep Program. (line 6) -* egrep utility: Bracket Expressions. (line 24) +* egrep utility: Bracket Expressions. (line 26) * egrep.awk program: Egrep Program. (line 54) * elements in arrays, assigning values: Assigning Elements. (line 6) * elements in arrays, deleting: Delete. (line 6) @@ -32106,20 +32184,19 @@ Index * END pattern, and profiling: Profiling. (line 62) * END pattern, assert() user-defined function and: Assert Function. (line 75) -* END pattern, backslash continuation and: Egrep Program. (line 223) * END pattern, Boolean patterns and: Expression Patterns. (line 70) * END pattern, exit statement and: Exit Statement. (line 12) * END pattern, next/nextfile statements and <1>: Next Statement. (line 45) * END pattern, next/nextfile statements and: I/O And BEGIN/END. - (line 37) + (line 36) * END pattern, operators and: Using BEGIN/END. (line 17) * END pattern, print statement and: I/O And BEGIN/END. (line 16) * ENDFILE pattern: BEGINFILE/ENDFILE. (line 6) * ENDFILE pattern, Boolean patterns and: Expression Patterns. (line 70) * endfile() user-defined function: Filetrans Function. (line 62) -* endgrent() function (C library): Group Functions. (line 213) -* endgrent() user-defined function: Group Functions. (line 216) +* endgrent() function (C library): Group Functions. (line 212) +* endgrent() user-defined function: Group Functions. (line 215) * endpwent() function (C library): Passwd Functions. (line 210) * endpwent() user-defined function: Passwd Functions. (line 213) * English, Steve: Advanced Features. (line 6) @@ -32132,7 +32209,7 @@ Index * equals sign (=), == operator <1>: Precedence. (line 65) * equals sign (=), == operator: Comparison Operators. (line 11) -* EREs (Extended Regular Expressions): Bracket Expressions. (line 24) +* EREs (Extended Regular Expressions): Bracket Expressions. (line 26) * ERRNO variable <1>: TCP/IP Networking. (line 54) * ERRNO variable: Auto-set. (line 82) * ERRNO variable, with BEGINFILE pattern: BEGINFILE/ENDFILE. (line 26) @@ -32165,8 +32242,8 @@ Index * exclamation point (!), !~ operator <3>: Comparison Operators. (line 11) * exclamation point (!), !~ operator <4>: Regexp Constants. (line 6) -* exclamation point (!), !~ operator <5>: Computed Regexps. (line 6) -* exclamation point (!), !~ operator <6>: Case-sensitivity. (line 26) +* exclamation point (!), !~ operator <5>: Case-sensitivity. (line 26) +* exclamation point (!), !~ operator <6>: Computed Regexps. (line 6) * exclamation point (!), !~ operator: Regexp Usage. (line 19) * exit statement: Exit Statement. (line 6) * exit status, of gawk: Exit Status. (line 6) @@ -32174,7 +32251,7 @@ Index * exit the debugger: Miscellaneous Debugger Commands. (line 99) * exp: Numeric Functions. (line 33) -* expand utility: Very Simple. (line 69) +* expand utility: Very Simple. (line 72) * Expat XML parser library: gawkextlib. (line 35) * exponent: Numeric Functions. (line 33) * expressions: Expressions. (line 6) @@ -32187,14 +32264,14 @@ Index * expressions, matching, See comparison expressions: Typing and Comparison. (line 9) * expressions, selecting: Conditional Exp. (line 6) -* Extended Regular Expressions (EREs): Bracket Expressions. (line 24) +* Extended Regular Expressions (EREs): Bracket Expressions. (line 26) * extension API: Extension API Description. (line 6) * extension API informational variables: Extension API Informational Variables. (line 6) * extension API version: Extension Versioning. (line 6) -* extension API, version number: Auto-set. (line 232) +* extension API, version number: Auto-set. (line 236) * extension example: Extension Example. (line 6) * extension registration: Registration Functions. (line 6) @@ -32213,13 +32290,15 @@ Index * extensions, common, BINMODE variable: PC Using. (line 33) * extensions, common, delete to delete entire arrays: Delete. (line 39) * extensions, common, fflush() function: I/O Functions. (line 43) -* extensions, common, func keyword: Definition Syntax. (line 89) +* extensions, common, func keyword: Definition Syntax. (line 92) * extensions, common, length() applied to an array: String Functions. (line 197) * extensions, common, RS as a regexp: gawk split records. (line 6) * extensions, common, single character fields: Single Character Fields. (line 6) * extensions, in gawk, not in POSIX awk: POSIX/GNU. (line 6) +* extensions, loading, @load directive: Loading Shared Libraries. + (line 8) * extensions, mawk: Common Extensions. (line 6) * extensions, where to find: gawkextlib. (line 6) * extract.awk program: Extract Program. (line 79) @@ -32253,7 +32332,7 @@ Index (line 6) * field separators, regular expressions as: Field Separators. (line 51) * field separators, See Also OFS: Changing Fields. (line 64) -* field separators, spaces as: Cut Program. (line 109) +* field separators, spaces as: Cut Program. (line 108) * fields <1>: Basic High Level. (line 73) * fields <2>: Fields. (line 6) * fields: Reading Files. (line 14) @@ -32270,6 +32349,7 @@ Index * FIELDWIDTHS variable <1>: User-modified. (line 37) * FIELDWIDTHS variable: Constant Size. (line 23) * file descriptors: Special FD. (line 6) +* file inclusion, @include directive: Include Files. (line 8) * file names, distinguishing: Auto-set. (line 56) * file names, in compatibility mode: Special Caveats. (line 9) * file names, standard streams in gawk: Special FD. (line 46) @@ -32308,7 +32388,7 @@ Index (line 47) * files, message object, specifying directory of: Explaining gettext. (line 54) -* files, multiple passes over: Other Arguments. (line 49) +* files, multiple passes over: Other Arguments. (line 53) * files, multiple, duplicating output into: Tee Program. (line 6) * files, output, See output files: Close Files And Pipes. (line 6) @@ -32324,7 +32404,7 @@ Index * files, reading, multiline records: Multiple Line. (line 6) * files, searching for regular expressions: Egrep Program. (line 6) * files, skipping: File Checking. (line 6) -* files, source, search path for: Programs Exercises. (line 63) +* files, source, search path for: Programs Exercises. (line 70) * files, splitting: Split Program. (line 6) * files, Texinfo, extracting programs from: Extract Program. (line 6) * find substring in string: String Functions. (line 155) @@ -32343,7 +32423,7 @@ Index (line 12) * FNR variable <1>: Auto-set. (line 107) * FNR variable: Records. (line 6) -* FNR variable, changing: Auto-set. (line 309) +* FNR variable, changing: Auto-set. (line 313) * for statement: For Statement. (line 6) * for statement, looping over arrays: Scanning an Array. (line 20) * fork() extension function: Extension Sample Fork. @@ -32396,6 +32476,7 @@ Index * FUNCTAB array: Auto-set. (line 123) * function calls: Function Calls. (line 6) * function calls, indirect: Indirect Calls. (line 6) +* function calls, indirect, @-notation for: Indirect Calls. (line 47) * function definition example: Function Example. (line 6) * function pointers: Indirect Calls. (line 6) * functions, arrays as parameters to: Pass By Value/Reference. @@ -32403,7 +32484,7 @@ Index * functions, built-in <1>: Functions. (line 6) * functions, built-in: Function Calls. (line 10) * functions, built-in, evaluation order: Calling Built-in. (line 30) -* functions, defining: Definition Syntax. (line 6) +* functions, defining: Definition Syntax. (line 9) * functions, library: Library Functions. (line 6) * functions, library, assertions: Assert Function. (line 6) * functions, library, associative arrays and: Library Names. (line 57) @@ -32426,9 +32507,9 @@ Index * functions, library, rounding numbers: Round Function. (line 6) * functions, library, user database, reading: Passwd Functions. (line 6) -* functions, names of <1>: Definition Syntax. (line 20) +* functions, names of <1>: Definition Syntax. (line 23) * functions, names of: Arrays. (line 18) -* functions, recursive: Definition Syntax. (line 79) +* functions, recursive: Definition Syntax. (line 82) * functions, string-translation: I18N Functions. (line 6) * functions, undefined: Pass By Value/Reference. (line 71) @@ -32440,17 +32521,17 @@ Index (line 47) * functions, user-defined, next/nextfile statements and: Next Statement. (line 45) -* G-d: Acknowledgments. (line 82) +* G-d: Acknowledgments. (line 92) * Garfinkle, Scott: Contributors. (line 34) * gawk program, dynamic profiling: Profiling. (line 179) -* gawk version: Auto-set. (line 207) +* gawk version: Auto-set. (line 211) * gawk, ARGIND variable in: Other Arguments. (line 12) * gawk, awk and <1>: This Manual. (line 14) -* gawk, awk and: Preface. (line 23) +* gawk, awk and: Preface. (line 21) * gawk, bitwise operations in: Bitwise Functions. (line 39) * gawk, break statement in: Break Statement. (line 51) * gawk, built-in variables and: Built-in Variables. (line 14) -* gawk, character classes and: Bracket Expressions. (line 98) +* gawk, character classes and: Bracket Expressions. (line 100) * gawk, coding style in: Adding Code. (line 39) * gawk, command-line options, and regular expressions: GNU Regexp Operators. (line 70) @@ -32460,7 +32541,7 @@ Index (line 6) * gawk, configuring, options: Additional Configuration Options. (line 6) -* gawk, continue statement in: Continue Statement. (line 43) +* gawk, continue statement in: Continue Statement. (line 44) * gawk, distribution: Distribution contents. (line 6) * gawk, ERRNO variable in <1>: TCP/IP Networking. (line 54) @@ -32469,7 +32550,7 @@ Index * gawk, ERRNO variable in <4>: Close Files And Pipes. (line 139) * gawk, ERRNO variable in: Getline. (line 19) -* gawk, escape sequences: Escape Sequences. (line 124) +* gawk, escape sequences: Escape Sequences. (line 132) * gawk, extensions, disabling: Options. (line 252) * gawk, features, adding: Adding Code. (line 6) * gawk, features, advanced: Advanced Features. (line 6) @@ -32487,7 +32568,7 @@ Index * gawk, IGNORECASE variable in <1>: Array Sorting Functions. (line 83) * gawk, IGNORECASE variable in <2>: String Functions. (line 58) -* gawk, IGNORECASE variable in <3>: Array Intro. (line 92) +* gawk, IGNORECASE variable in <3>: Array Intro. (line 94) * gawk, IGNORECASE variable in <4>: User-modified. (line 76) * gawk, IGNORECASE variable in: Case-sensitivity. (line 26) * gawk, implementation issues: Notes. (line 6) @@ -32501,7 +32582,7 @@ Index (line 13) * gawk, interpreter, adding code to: Using Internal File Ops. (line 6) -* gawk, interval expressions and: Regexp Operators. (line 140) +* gawk, interval expressions and: Regexp Operators. (line 139) * gawk, line continuation in: Conditional Exp. (line 34) * gawk, LINT variable in: User-modified. (line 88) * gawk, list of contributors to: Contributors. (line 6) @@ -32510,27 +32591,27 @@ Index * gawk, newlines in: Statements/Lines. (line 12) * gawk, octal numbers and: Nondecimal-numbers. (line 42) * gawk, OS/2 version of: PC Using. (line 16) -* gawk, PROCINFO array in <1>: Two-way I/O. (line 117) +* gawk, PROCINFO array in <1>: Two-way I/O. (line 99) * gawk, PROCINFO array in <2>: Time Functions. (line 47) -* gawk, PROCINFO array in: Auto-set. (line 136) +* gawk, PROCINFO array in: Auto-set. (line 137) * gawk, regexp constants and: Using Constant Regexps. (line 28) * gawk, regular expressions, case sensitivity: Case-sensitivity. (line 26) * gawk, regular expressions, operators: GNU Regexp Operators. (line 6) -* gawk, regular expressions, precedence: Regexp Operators. (line 162) -* gawk, RT variable in <1>: Auto-set. (line 265) +* gawk, regular expressions, precedence: Regexp Operators. (line 161) +* gawk, RT variable in <1>: Auto-set. (line 269) * gawk, RT variable in <2>: Multiple Line. (line 129) * gawk, RT variable in: awk split records. (line 124) -* gawk, See Also awk: Preface. (line 36) +* gawk, See Also awk: Preface. (line 34) * gawk, source code, obtaining: Getting. (line 6) * gawk, splitting fields and: Constant Size. (line 88) * gawk, string-translation functions: I18N Functions. (line 6) -* gawk, SYMTAB array in: Auto-set. (line 269) +* gawk, SYMTAB array in: Auto-set. (line 273) * gawk, TEXTDOMAIN variable in: User-modified. (line 152) * gawk, timestamps: Time Functions. (line 6) -* gawk, uses for: Preface. (line 36) +* gawk, uses for: Preface. (line 34) * gawk, versions of, information about, printing: Options. (line 298) * gawk, VMS version of: VMS Installation. (line 6) * gawk, word-boundary operator: GNU Regexp Operators. @@ -32547,12 +32628,12 @@ Index * getaddrinfo() function (C library): TCP/IP Networking. (line 38) * getgrent() function (C library): Group Functions. (line 6) * getgrent() user-defined function: Group Functions. (line 6) -* getgrgid() function (C library): Group Functions. (line 184) -* getgrgid() user-defined function: Group Functions. (line 187) -* getgrnam() function (C library): Group Functions. (line 173) -* getgrnam() user-defined function: Group Functions. (line 178) -* getgruser() function (C library): Group Functions. (line 193) -* getgruser() function, user-defined: Group Functions. (line 196) +* getgrgid() function (C library): Group Functions. (line 183) +* getgrgid() user-defined function: Group Functions. (line 186) +* getgrnam() function (C library): Group Functions. (line 172) +* getgrnam() user-defined function: Group Functions. (line 177) +* getgruser() function (C library): Group Functions. (line 192) +* getgruser() function, user-defined: Group Functions. (line 195) * getline command: Reading Files. (line 20) * getline command, _gr_init() user-defined function: Group Functions. (line 83) @@ -32561,7 +32642,7 @@ Index (line 6) * getline command, coprocesses, using from: Getline/Coprocess. (line 6) -* getline command, deadlock and: Two-way I/O. (line 70) +* getline command, deadlock and: Two-way I/O. (line 52) * getline command, explicit input with: Getline. (line 6) * getline command, FILENAME variable and: Getline Notes. (line 19) * getline command, return values: Getline. (line 19) @@ -32592,7 +32673,7 @@ Index * git utility: gawkextlib. (line 29) * Git, use of for gawk source code: Derived Files. (line 6) * GNITS mailing list: Acknowledgments. (line 52) -* GNU awk, See gawk: Preface. (line 53) +* GNU awk, See gawk: Preface. (line 51) * GNU Free Documentation License: GNU Free Documentation License. (line 7) * GNU General Public License: Glossary. (line 305) @@ -32613,7 +32694,7 @@ Index * Grigera, Juan: Contributors. (line 57) * group database, reading: Group Functions. (line 6) * group file: Group Functions. (line 6) -* group ID of gawk user: Auto-set. (line 180) +* group ID of gawk user: Auto-set. (line 184) * groups, information about: Group Functions. (line 6) * gsub <1>: String Functions. (line 139) * gsub: Using Constant Regexps. @@ -32653,7 +32734,7 @@ Index * ignore breakpoint: Breakpoint Control. (line 87) * ignore debugger command: Breakpoint Control. (line 87) * IGNORECASE variable: User-modified. (line 76) -* IGNORECASE variable, and array indices: Array Intro. (line 92) +* IGNORECASE variable, and array indices: Array Intro. (line 94) * IGNORECASE variable, and array sorting functions: Array Sorting Functions. (line 83) * IGNORECASE variable, in example programs: Library Functions. @@ -32674,12 +32755,14 @@ Index (line 43) * in operator, order of array access: Scanning an Array. (line 48) * in operator, testing if array element exists: Reference to Elements. - (line 37) + (line 38) * in operator, use in loops: Scanning an Array. (line 17) +* including files, @include directive: Include Files. (line 8) * increment operators: Increment Ops. (line 6) * index: String Functions. (line 155) * indexing arrays: Array Intro. (line 50) * indirect function calls: Indirect Calls. (line 6) +* indirect function calls, @-notation: Indirect Calls. (line 47) * infinite precision: Arbitrary Precision Arithmetic. (line 6) * info debugger command: Debugger Info. (line 13) @@ -32693,7 +32776,7 @@ Index * input files, examples: Sample Data Files. (line 6) * input files, reading: Reading Files. (line 6) * input files, running awk without: Read Terminal. (line 6) -* input files, variable assignments and: Other Arguments. (line 19) +* input files, variable assignments and: Other Arguments. (line 23) * input pipeline: Getline/Pipe. (line 9) * input record, length of: String Functions. (line 174) * input redirection: Getline/File. (line 6) @@ -32707,7 +32790,7 @@ Index * input/output functions: I/O Functions. (line 6) * input/output, binary: User-modified. (line 15) * input/output, from BEGIN and END: I/O And BEGIN/END. (line 6) -* input/output, two-way: Two-way I/O. (line 44) +* input/output, two-way: Two-way I/O. (line 25) * insomnia, cure for: Alarm Program. (line 6) * installation, VMS: VMS Installation. (line 6) * installing gawk: Installation. (line 6) @@ -32726,7 +32809,7 @@ Index (line 13) * internationalization, localization: User-modified. (line 152) * internationalization, localization, character classes: Bracket Expressions. - (line 98) + (line 100) * internationalization, localization, gawk and: Internationalization. (line 13) * internationalization, localization, locale categories: Explaining gettext. @@ -32738,7 +32821,7 @@ Index * internationalizing a program: Explaining gettext. (line 6) * interpreted programs <1>: Glossary. (line 356) * interpreted programs: Basic High Level. (line 15) -* interval expressions, regexp operator: Regexp Operators. (line 117) +* interval expressions, regexp operator: Regexp Operators. (line 116) * inventory-shipped file: Sample Data Files. (line 32) * invoke shell command: I/O Functions. (line 75) * isarray: Type Functions. (line 11) @@ -32767,7 +32850,7 @@ Index * Kernighan, Brian <7>: Concatenation. (line 6) * Kernighan, Brian <8>: Getline/Pipe. (line 6) * Kernighan, Brian <9>: Acknowledgments. (line 76) -* Kernighan, Brian <10>: Conventions. (line 34) +* Kernighan, Brian <10>: Conventions. (line 38) * Kernighan, Brian: History. (line 17) * kill command, dynamic profiling: Profiling. (line 188) * Knights, jedi: Undocumented. (line 6) @@ -32777,16 +32860,15 @@ Index * labels.awk program: Labels Program. (line 51) * Langston, Peter: Advanced Features. (line 6) * languages, data-driven: Basic High Level. (line 85) -* LC_ALL locale category: Explaining gettext. (line 121) +* LC_ALL locale category: Explaining gettext. (line 117) * LC_COLLATE locale category: Explaining gettext. (line 94) * LC_CTYPE locale category: Explaining gettext. (line 98) * LC_MESSAGES locale category: Explaining gettext. (line 88) * LC_MESSAGES locale category, bindtextdomain() function (gawk): Programmer i18n. - (line 88) + (line 99) * LC_MONETARY locale category: Explaining gettext. (line 104) * LC_NUMERIC locale category: Explaining gettext. (line 108) -* LC_RESPONSE locale category: Explaining gettext. (line 112) -* LC_TIME locale category: Explaining gettext. (line 116) +* LC_TIME locale category: Explaining gettext. (line 112) * left angle bracket (<), < operator <1>: Precedence. (line 65) * left angle bracket (<), < operator: Comparison Operators. (line 11) @@ -32842,7 +32924,7 @@ Index * lint checking, empty programs: Command Line. (line 16) * lint checking, issuing warnings: Options. (line 185) * lint checking, POSIXLY_CORRECT environment variable: Options. - (line 338) + (line 336) * lint checking, undefined functions: Pass By Value/Reference. (line 88) * LINT variable: User-modified. (line 88) @@ -32853,6 +32935,8 @@ Index * list debugger command: Miscellaneous Debugger Commands. (line 72) * list function definitions, in debugger: Debugger Info. (line 30) +* loading extensions, @load directive: Loading Shared Libraries. + (line 8) * loading, extensions: Options. (line 173) * local variables, in a function: Variable Scope. (line 6) * locale categories: Explaining gettext. (line 81) @@ -32898,13 +32982,13 @@ Index * matching, expressions, See comparison expressions: Typing and Comparison. (line 9) * matching, leftmost longest: Multiple Line. (line 26) -* matching, null strings: Gory Details. (line 164) +* matching, null strings: Gory Details. (line 143) * mawk utility <1>: Other Versions. (line 44) * mawk utility <2>: Nextfile Statement. (line 47) * mawk utility <3>: Concatenation. (line 36) * mawk utility <4>: Getline/Pipe. (line 62) -* mawk utility: Escape Sequences. (line 124) -* maximum precision supported by MPFR library: Auto-set. (line 221) +* mawk utility: Escape Sequences. (line 132) +* maximum precision supported by MPFR library: Auto-set. (line 225) * McIlroy, Doug: Glossary. (line 149) * McPhee, Patrick: Contributors. (line 100) * message object files: Explaining gettext. (line 42) @@ -32916,8 +33000,8 @@ Index (line 54) * messages from extensions: Printing Messages. (line 6) * metacharacters in regular expressions: Regexp Operators. (line 6) -* metacharacters, escape sequences for: Escape Sequences. (line 130) -* minimum precision supported by MPFR library: Auto-set. (line 224) +* metacharacters, escape sequences for: Escape Sequences. (line 138) +* minimum precision supported by MPFR library: Auto-set. (line 228) * mktime: Time Functions. (line 25) * modifiers, in format specifiers: Format Modifiers. (line 6) * monetary information, localization: Explaining gettext. (line 104) @@ -32931,11 +33015,10 @@ Index * names, arrays/variables <1>: Library Names. (line 6) * names, arrays/variables: Arrays. (line 18) * names, functions <1>: Library Names. (line 6) -* names, functions: Definition Syntax. (line 20) +* names, functions: Definition Syntax. (line 23) * namespace issues <1>: Library Names. (line 6) * namespace issues: Arrays. (line 18) -* namespace issues, functions: Definition Syntax. (line 20) -* nawk utility: Names. (line 10) +* namespace issues, functions: Definition Syntax. (line 23) * NetBSD: Glossary. (line 611) * networks, programming: TCP/IP Networking. (line 6) * networks, support for: Special Network. (line 6) @@ -32955,14 +33038,14 @@ Index (line 43) * next file statement: Feature History. (line 169) * next statement <1>: Next Statement. (line 6) -* next statement: Boolean Ops. (line 85) -* next statement, BEGIN/END patterns and: I/O And BEGIN/END. (line 37) +* next statement: Boolean Ops. (line 93) +* next statement, BEGIN/END patterns and: I/O And BEGIN/END. (line 36) * next statement, BEGINFILE/ENDFILE patterns and: BEGINFILE/ENDFILE. (line 49) * next statement, user-defined functions and: Next Statement. (line 45) * nextfile statement: Nextfile Statement. (line 6) * nextfile statement, BEGIN/END patterns and: I/O And BEGIN/END. - (line 37) + (line 36) * nextfile statement, BEGINFILE/ENDFILE patterns and: BEGINFILE/ENDFILE. (line 26) * nextfile statement, user-defined functions and: Nextfile Statement. @@ -32978,9 +33061,9 @@ Index * non-existent array elements: Reference to Elements. (line 23) * not Boolean-logic operator: Boolean Ops. (line 6) -* NR variable <1>: Auto-set. (line 131) +* NR variable <1>: Auto-set. (line 132) * NR variable: Records. (line 6) -* NR variable, changing: Auto-set. (line 309) +* NR variable, changing: Auto-set. (line 313) * null strings <1>: Basic Data Typing. (line 26) * null strings <2>: Truth Values. (line 6) * null strings <3>: Regexp Field Splitting. @@ -32992,7 +33075,7 @@ Index (line 43) * null strings, converting numbers to strings: Strings And Numbers. (line 21) -* null strings, matching: Gory Details. (line 164) +* null strings, matching: Gory Details. (line 143) * number as string of bits: Bitwise Functions. (line 109) * number of array elements: String Functions. (line 197) * number sign (#), #! (executable scripts): Executable Scripts. @@ -33014,7 +33097,6 @@ Index * numeric, output format: OFMT. (line 6) * numeric, strings: Variable Typing. (line 6) * o debugger command (alias for option): Debugger Info. (line 57) -* oawk utility: Names. (line 10) * obsolete features: Obsolete. (line 6) * octal numbers: Nondecimal-numbers. (line 6) * octal values, enabling interpretation of: Options. (line 211) @@ -33095,9 +33177,9 @@ Index * p debugger command (alias for print): Viewing And Changing Data. (line 36) * Papadopoulos, Panos: Contributors. (line 128) -* parent process ID of gawk process: Auto-set. (line 189) +* parent process ID of gawk process: Auto-set. (line 193) * parentheses (), in a profile: Profiling. (line 146) -* parentheses (), regexp operator: Regexp Operators. (line 80) +* parentheses (), regexp operator: Regexp Operators. (line 81) * password file: Passwd Functions. (line 16) * patsplit: String Functions. (line 294) * patterns: Patterns and Actions. @@ -33135,23 +33217,23 @@ Index * plus sign (+), ++ operator: Increment Ops. (line 11) * plus sign (+), += operator <1>: Precedence. (line 95) * plus sign (+), += operator: Assignment Ops. (line 82) -* plus sign (+), regexp operator: Regexp Operators. (line 103) +* plus sign (+), regexp operator: Regexp Operators. (line 105) * pointers to functions: Indirect Calls. (line 6) -* portability: Escape Sequences. (line 94) +* portability: Escape Sequences. (line 102) * portability, #! (executable scripts): Executable Scripts. (line 33) * portability, ** operator and: Arithmetic Ops. (line 81) * portability, **= operator and: Assignment Ops. (line 143) -* portability, ARGV variable: Executable Scripts. (line 42) +* portability, ARGV variable: Executable Scripts. (line 59) * portability, backslash continuation and: Statements/Lines. (line 30) * portability, backslash in escape sequences: Escape Sequences. - (line 112) + (line 120) * portability, close() function and: Close Files And Pipes. (line 81) * portability, data files as single record: gawk split records. (line 65) * portability, deleting array elements: Delete. (line 56) * portability, example programs: Library Functions. (line 42) -* portability, functions, defining: Definition Syntax. (line 105) +* portability, functions, defining: Definition Syntax. (line 108) * portability, gawk: New Ports. (line 6) * portability, gettext library and: Explaining gettext. (line 11) * portability, internationalization and: I18N Portability. (line 6) @@ -33162,7 +33244,7 @@ Index * portability, NF variable, decrementing: Changing Fields. (line 115) * portability, operators: Increment Ops. (line 60) * portability, operators, not in POSIX awk: Precedence. (line 98) -* portability, POSIXLY_CORRECT environment variable: Options. (line 358) +* portability, POSIXLY_CORRECT environment variable: Options. (line 356) * portability, substr() function: String Functions. (line 510) * portable object files <1>: Translator i18n. (line 6) * portable object files: Explaining gettext. (line 37) @@ -33183,43 +33265,43 @@ Index * POSIX awk, < operator and: Getline/File. (line 26) * POSIX awk, arithmetic operators and: Arithmetic Ops. (line 30) * POSIX awk, backslashes in string constants: Escape Sequences. - (line 112) + (line 120) * POSIX awk, BEGIN/END patterns: I/O And BEGIN/END. (line 16) -* POSIX awk, bracket expressions and: Bracket Expressions. (line 24) +* POSIX awk, bracket expressions and: Bracket Expressions. (line 26) * POSIX awk, bracket expressions and, character classes: Bracket Expressions. - (line 30) + (line 32) * POSIX awk, break statement and: Break Statement. (line 51) * POSIX awk, changes in awk versions: POSIX. (line 6) -* POSIX awk, continue statement and: Continue Statement. (line 43) +* POSIX awk, continue statement and: Continue Statement. (line 44) * POSIX awk, CONVFMT variable and: User-modified. (line 30) * POSIX awk, date utility and: Time Functions. (line 254) * POSIX awk, field separators and <1>: Field Splitting Summary. (line 40) * POSIX awk, field separators and: Fields. (line 6) * POSIX awk, FS variable and: User-modified. (line 60) -* POSIX awk, function keyword in: Definition Syntax. (line 89) -* POSIX awk, functions and, gsub()/sub(): Gory Details. (line 54) +* POSIX awk, function keyword in: Definition Syntax. (line 92) +* POSIX awk, functions and, gsub()/sub(): Gory Details. (line 90) * POSIX awk, functions and, length(): String Functions. (line 176) * POSIX awk, GNU long options and: Options. (line 15) -* POSIX awk, interval expressions in: Regexp Operators. (line 136) +* POSIX awk, interval expressions in: Regexp Operators. (line 135) * POSIX awk, next/nextfile statements and: Next Statement. (line 45) * POSIX awk, numeric strings and: Variable Typing. (line 6) * POSIX awk, OFMT variable and <1>: Strings And Numbers. (line 57) * POSIX awk, OFMT variable and: OFMT. (line 27) * POSIX awk, period (.), using: Regexp Operators. (line 51) * POSIX awk, printf format strings and: Format Modifiers. (line 159) -* POSIX awk, regular expressions and: Regexp Operators. (line 162) +* POSIX awk, regular expressions and: Regexp Operators. (line 161) * POSIX awk, timestamps and: Time Functions. (line 6) * POSIX awk, | I/O operator and: Getline/Pipe. (line 55) * POSIX mode: Options. (line 252) -* POSIX, awk and: Preface. (line 23) +* 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 338) +* POSIXLY_CORRECT environment variable: Options. (line 336) * PREC variable: User-modified. (line 124) * precedence <1>: Precedence. (line 6) * precedence: Increment Ops. (line 60) -* precedence, regexp operators: Regexp Operators. (line 157) +* precedence, regexp operators: Regexp Operators. (line 156) * print debugger command: Viewing And Changing Data. (line 36) * print statement: Printing. (line 16) @@ -33258,26 +33340,25 @@ Index * printing, unduplicated lines of text: Uniq Program. (line 6) * printing, user information: Id Program. (line 6) * private variables: Library Names. (line 11) -* process group idIDof gawk process: Auto-set. (line 183) -* process ID of gawk process: Auto-set. (line 186) -* processes, two-way communications with: Two-way I/O. (line 23) +* process group idIDof gawk process: Auto-set. (line 187) +* process ID of gawk process: Auto-set. (line 190) +* processes, two-way communications with: Two-way I/O. (line 6) * processing data: Basic High Level. (line 6) * PROCINFO array <1>: Passwd Functions. (line 6) * PROCINFO array <2>: Time Functions. (line 47) -* PROCINFO array: Auto-set. (line 136) -* PROCINFO array, and communications via ptys: Two-way I/O. (line 117) +* PROCINFO array: Auto-set. (line 137) +* PROCINFO array, and communications via ptys: Two-way I/O. (line 99) * PROCINFO array, and group membership: Group Functions. (line 6) * PROCINFO array, and user and group ID numbers: Id Program. (line 15) * PROCINFO array, testing the field splitting: Passwd Functions. (line 161) -* PROCINFO array, uses: Auto-set. (line 242) +* PROCINFO array, uses: Auto-set. (line 246) * PROCINFO, values of sorted_in: Controlling Scanning. (line 26) * profiling awk programs: Profiling. (line 6) * profiling awk programs, dynamically: Profiling. (line 179) -* program identifiers: Auto-set. (line 154) +* program identifiers: Auto-set. (line 155) * program, definition of: Getting Started. (line 21) -* programmers, attractiveness of: Two-way I/O. (line 6) * programming conventions, --non-decimal-data option: Nondecimal Data. (line 36) * programming conventions, ARGC/ARGV variables: Auto-set. (line 35) @@ -33287,7 +33368,7 @@ Index * programming conventions, functions, calling: Calling Built-in. (line 10) * programming conventions, functions, writing: Definition Syntax. - (line 61) + (line 64) * programming conventions, gawk extensions: Internal File Ops. (line 45) * programming conventions, private variable names: Library Names. @@ -33307,7 +33388,7 @@ Index * question mark (?), ?: operator: Precedence. (line 92) * question mark (?), regexp operator <1>: GNU Regexp Operators. (line 59) -* question mark (?), regexp operator: Regexp Operators. (line 112) +* question mark (?), regexp operator: Regexp Operators. (line 111) * QuikTrim Awk: Other Versions. (line 135) * quit debugger command: Miscellaneous Debugger Commands. (line 99) @@ -33320,12 +33401,12 @@ Index * Rakitzis, Byron: History Sorting. (line 25) * Ramey, Chet <1>: General Data Types. (line 6) * Ramey, Chet: Acknowledgments. (line 60) -* rand: Numeric Functions. (line 49) +* rand: Numeric Functions. (line 50) * random numbers, Cliff: Cliff Random Function. (line 6) * random numbers, rand()/srand() functions: Numeric Functions. - (line 49) -* random numbers, seed of: Numeric Functions. (line 79) + (line 50) +* random numbers, seed of: Numeric Functions. (line 80) * range expressions (regexps): Bracket Expressions. (line 6) * range patterns: Ranges. (line 6) * range patterns, line continuation and: Ranges. (line 65) @@ -33357,7 +33438,7 @@ Index * records, splitting input into: Records. (line 6) * records, terminating: awk split records. (line 124) * records, treating files as: gawk split records. (line 92) -* recursive functions: Definition Syntax. (line 79) +* recursive functions: Definition Syntax. (line 82) * redirect gawk output, in debugger: Debugger Info. (line 72) * redirection of input: Getline/File. (line 6) * redirection of output: Redirection. (line 6) @@ -33407,7 +33488,7 @@ Index * regular expressions, operators, gawk: GNU Regexp Operators. (line 6) * regular expressions, operators, precedence of: Regexp Operators. - (line 157) + (line 156) * regular expressions, searching for: Egrep Program. (line 6) * relational operators, See comparison operators: Typing and Comparison. (line 9) @@ -33417,7 +33498,7 @@ Index * return statement, user-defined functions: Return Statement. (line 6) * return value, close() function: Close Files And Pipes. (line 131) -* rev() user-defined function: Function Example. (line 53) +* rev() user-defined function: Function Example. (line 54) * revoutput extension: Extension Sample Revout. (line 11) * revtwoway extension: Extension Sample Rev2way. @@ -33435,7 +33516,7 @@ Index * right shift: Bitwise Functions. (line 52) * right shift, bitwise: Bitwise Functions. (line 32) * Ritchie, Dennis: Basic Data Typing. (line 54) -* RLENGTH variable: Auto-set. (line 252) +* RLENGTH variable: Auto-set. (line 256) * RLENGTH variable, match() function and: String Functions. (line 224) * Robbins, Arnold <1>: Future Extensions. (line 6) * Robbins, Arnold <2>: Bugs. (line 32) @@ -33445,13 +33526,13 @@ Index * Robbins, Arnold <6>: Passwd Functions. (line 90) * Robbins, Arnold <7>: Getline/Pipe. (line 39) * Robbins, Arnold: Command Line Field Separator. - (line 73) + (line 74) * Robbins, Bill: Getline/Pipe. (line 39) -* Robbins, Harry: Acknowledgments. (line 82) -* Robbins, Jean: Acknowledgments. (line 82) +* Robbins, Harry: Acknowledgments. (line 92) +* Robbins, Jean: Acknowledgments. (line 92) * Robbins, Miriam <1>: Passwd Functions. (line 90) * Robbins, Miriam <2>: Getline/Pipe. (line 39) -* Robbins, Miriam: Acknowledgments. (line 82) +* Robbins, Miriam: Acknowledgments. (line 92) * Rommel, Kai Uwe: Contributors. (line 42) * round to nearest integer: Numeric Functions. (line 38) * round() user-defined function: Round Function. (line 16) @@ -33461,9 +33542,9 @@ Index * RS variable: awk split records. (line 12) * RS variable, multiline records and: Multiple Line. (line 17) * rshift: Bitwise Functions. (line 52) -* RSTART variable: Auto-set. (line 258) +* RSTART variable: Auto-set. (line 262) * RSTART variable, match() function and: String Functions. (line 224) -* RT variable <1>: Auto-set. (line 265) +* RT variable <1>: Auto-set. (line 269) * RT variable <2>: Multiple Line. (line 129) * RT variable: awk split records. (line 124) * Rubin, Paul <1>: Contributors. (line 15) @@ -33483,7 +33564,7 @@ Index * scanning arrays: Scanning an Array. (line 6) * scanning multidimensional arrays: Multiscanning. (line 11) * Schorr, Andrew <1>: Contributors. (line 133) -* Schorr, Andrew <2>: Auto-set. (line 292) +* Schorr, Andrew <2>: Auto-set. (line 296) * Schorr, Andrew: Acknowledgments. (line 60) * Schreiber, Bert: Acknowledgments. (line 38) * Schreiber, Rita: Acknowledgments. (line 38) @@ -33491,11 +33572,11 @@ Index * search in string: String Functions. (line 155) * search paths <1>: VMS Running. (line 58) * search paths <2>: PC Using. (line 10) -* search paths: Programs Exercises. (line 63) +* search paths: Programs Exercises. (line 70) * search paths, for loadable extensions: AWKLIBPATH Variable. (line 6) * search paths, for source files <1>: VMS Running. (line 58) * search paths, for source files <2>: PC Using. (line 10) -* search paths, for source files <3>: Programs Exercises. (line 63) +* search paths, for source files <3>: Programs Exercises. (line 70) * search paths, for source files: AWKPATH Variable. (line 6) * searching, files for regular expressions: Egrep Program. (line 6) * searching, for words: Dupword Program. (line 6) @@ -33503,7 +33584,7 @@ Index * sed utility <2>: Simple Sed. (line 6) * sed utility: Field Splitting Summary. (line 46) -* seeding random number generator: Numeric Functions. (line 79) +* seeding random number generator: Numeric Functions. (line 80) * semicolon (;), AWKPATH variable and: PC Using. (line 10) * semicolon (;), separating statements in actions <1>: Statements. (line 10) @@ -33527,8 +33608,7 @@ Index * set directory of message catalogs: I18N Functions. (line 12) * set watchpoint: Viewing And Changing Data. (line 67) -* shadowing of variable values: Definition Syntax. (line 67) -* shell quoting, double quote: Read Terminal. (line 25) +* shadowing of variable values: Definition Syntax. (line 70) * shell quoting, rules for: Quoting. (line 6) * shells, piping commands into: Redirection. (line 142) * shells, quoting: Using Shell Variables. @@ -33552,7 +33632,7 @@ Index * side effects <1>: Increment Ops. (line 11) * side effects: Concatenation. (line 41) * side effects, array indexing: Reference to Elements. - (line 42) + (line 43) * side effects, asort() function: Array Sorting Functions. (line 24) * side effects, assignment expressions: Assignment Ops. (line 23) @@ -33565,22 +33645,21 @@ Index * sidebar, A Constant's Base Does Not Affect Its Value: Nondecimal-numbers. (line 64) * sidebar, Backslash Before Regular Characters: Escape Sequences. - (line 110) + (line 118) * sidebar, Changing FS Does Not Affect the Fields: Field Splitting Summary. (line 38) -* sidebar, Changing NR and FNR: Auto-set. (line 307) +* sidebar, Changing NR and FNR: Auto-set. (line 311) * sidebar, Controlling Output Buffering with system(): I/O Functions. (line 138) * sidebar, Escape Sequences for Metacharacters: Escape Sequences. - (line 128) + (line 136) * sidebar, FS and IGNORECASE: Field Splitting Summary. (line 64) * sidebar, Interactive Versus Noninteractive Buffering: I/O Functions. (line 107) -* sidebar, Matching the Null String: Gory Details. (line 162) +* sidebar, Matching the Null String: Gory Details. (line 141) * sidebar, Operator Evaluation Order: Increment Ops. (line 58) * sidebar, Piping into sh: Redirection. (line 140) -* sidebar, Portability Issues with #!: Executable Scripts. (line 31) * sidebar, Pre-POSIX awk Used OFMT For String Conversion: Strings And Numbers. (line 55) * sidebar, Recipe For A Programming Language: History. (line 6) @@ -33589,6 +33668,7 @@ Index (line 83) * sidebar, Syntactic Ambiguities Between /= and Regular Expressions: Assignment Ops. (line 146) +* sidebar, Understanding #!: Executable Scripts. (line 31) * sidebar, Understanding $0: Changing Fields. (line 134) * sidebar, Using \n in Bracket Expressions of Dynamic Regexps: Computed Regexps. (line 57) @@ -33605,8 +33685,8 @@ Index * SIGUSR1 signal, for dynamic profiling: Profiling. (line 188) * silent debugger command: Debugger Execution Control. (line 10) -* sin: Numeric Functions. (line 90) -* sine: Numeric Functions. (line 90) +* sin: Numeric Functions. (line 91) +* sine: Numeric Functions. (line 91) * single quote ('): One-shot. (line 15) * single quote (') in gawk command lines: Long. (line 33) * single quote ('), in shell commands: Quoting. (line 48) @@ -33617,7 +33697,7 @@ Index * single-step execution, in the debugger: Debugger Execution Control. (line 43) * Skywalker, Luke: Undocumented. (line 6) -* sleep utility: Alarm Program. (line 111) +* sleep utility: Alarm Program. (line 110) * sleep() extension function: Extension Sample Time. (line 22) * Solaris, POSIX-compliant awk: Other Versions. (line 96) @@ -33626,7 +33706,7 @@ Index * sort function, arrays, sorting: Array Sorting Functions. (line 6) * sort utility: Word Sorting. (line 50) -* sort utility, coprocesses and: Two-way I/O. (line 83) +* sort utility, coprocesses and: Two-way I/O. (line 65) * sorting characters in different languages: Explaining gettext. (line 94) * source code, awka: Other Versions. (line 64) @@ -33643,8 +33723,8 @@ Index * source code, QSE Awk: Other Versions. (line 131) * source code, QuikTrim Awk: Other Versions. (line 135) * source code, Solaris awk: Other Versions. (line 96) -* source files, search path for: Programs Exercises. (line 63) -* sparse arrays: Array Intro. (line 71) +* source files, search path for: Programs Exercises. (line 70) +* sparse arrays: Array Intro. (line 72) * Spencer, Henry: Glossary. (line 11) * split: String Functions. (line 313) * split string into array: String Functions. (line 294) @@ -33656,10 +33736,10 @@ Index * sprintf() function, OFMT variable and: User-modified. (line 114) * sprintf() function, print/printf statements and: Round Function. (line 6) -* sqrt: Numeric Functions. (line 93) +* sqrt: Numeric Functions. (line 94) * square brackets ([]), regexp operator: Regexp Operators. (line 56) -* square root: Numeric Functions. (line 93) -* srand: Numeric Functions. (line 97) +* square root: Numeric Functions. (line 94) +* srand: Numeric Functions. (line 98) * stack frame: Debugging Terms. (line 10) * Stallman, Richard <1>: Glossary. (line 296) * Stallman, Richard <2>: Contributors. (line 23) @@ -33731,9 +33811,9 @@ Index * substr: String Functions. (line 479) * substring: String Functions. (line 479) * Sumner, Andrew: Other Versions. (line 64) -* supplementary groups of gawk process: Auto-set. (line 237) +* supplementary groups of gawk process: Auto-set. (line 241) * switch statement: Switch Statement. (line 6) -* SYMTAB array: Auto-set. (line 269) +* SYMTAB array: Auto-set. (line 273) * syntactic ambiguity: /= operator vs. /=.../ regexp constant: Assignment Ops. (line 148) * system: I/O Functions. (line 75) @@ -33772,12 +33852,12 @@ Index * tilde (~), ~ operator <3>: Comparison Operators. (line 11) * tilde (~), ~ operator <4>: Regexp Constants. (line 6) -* tilde (~), ~ operator <5>: Computed Regexps. (line 6) -* tilde (~), ~ operator <6>: Case-sensitivity. (line 26) +* tilde (~), ~ operator <5>: Case-sensitivity. (line 26) +* tilde (~), ~ operator <6>: Computed Regexps. (line 6) * tilde (~), ~ operator: Regexp Usage. (line 19) * time functions: Time Functions. (line 6) * time, alarm clock example program: Alarm Program. (line 11) -* time, localization and: Explaining gettext. (line 116) +* time, localization and: Explaining gettext. (line 112) * time, managing: Getlocaltime Function. (line 6) * time, retrieving: Time Functions. (line 17) @@ -33800,7 +33880,7 @@ Index (line 37) * troubleshooting, awk uses FS not IFS: Field Separators. (line 30) * troubleshooting, backslash before nonspecial character: Escape Sequences. - (line 112) + (line 120) * troubleshooting, division: Arithmetic Ops. (line 44) * troubleshooting, fatal errors, field widths, specifying: Constant Size. (line 23) @@ -33856,11 +33936,11 @@ Index * uniq.awk program: Uniq Program. (line 65) * Unix: Glossary. (line 611) * Unix awk, backslashes in escape sequences: Escape Sequences. - (line 124) + (line 132) * Unix awk, close() function and: Close Files And Pipes. (line 131) * Unix awk, password files, field separators and: Command Line Field Separator. - (line 64) + (line 65) * Unix, awk scripts and: Executable Scripts. (line 6) * UNIXROOT variable, on OS/2 systems: PC Using. (line 16) * unsigned integers: Computer Arithmetic. (line 41) @@ -33879,7 +33959,7 @@ Index * USR1 signal, for dynamic profiling: Profiling. (line 188) * values, numeric: Basic Data Typing. (line 13) * values, string: Basic Data Typing. (line 13) -* variable assignments and input files: Other Arguments. (line 19) +* variable assignments and input files: Other Arguments. (line 23) * variable typing: Typing and Comparison. (line 9) * variables <1>: Basic Data Typing. (line 6) @@ -33904,21 +33984,21 @@ Index * variables, names of: Arrays. (line 18) * variables, private: Library Names. (line 11) * variables, setting: Options. (line 32) -* variables, shadowing: Definition Syntax. (line 67) +* variables, shadowing: Definition Syntax. (line 70) * variables, types of: Assignment Ops. (line 40) * variables, types of, comparison expressions and: Typing and Comparison. (line 9) * variables, uninitialized, as array subscripts: Uninitialized Subscripts. (line 6) * variables, user-defined: Variables. (line 6) -* version of gawk: Auto-set. (line 207) -* version of gawk extension API: Auto-set. (line 232) -* version of GNU MP library: Auto-set. (line 218) -* version of GNU MPFR library: Auto-set. (line 214) +* version of gawk: Auto-set. (line 211) +* version of gawk extension API: Auto-set. (line 236) +* version of GNU MP library: Auto-set. (line 222) +* version of GNU MPFR library: Auto-set. (line 218) * vertical bar (|): Regexp Operators. (line 70) * vertical bar (|), | operator (I/O) <1>: Precedence. (line 65) * vertical bar (|), | operator (I/O): Getline/Pipe. (line 9) -* vertical bar (|), |& operator (I/O) <1>: Two-way I/O. (line 44) +* vertical bar (|), |& operator (I/O) <1>: Two-way I/O. (line 25) * vertical bar (|), |& operator (I/O) <2>: Precedence. (line 65) * vertical bar (|), |& operator (I/O): Getline/Coprocess. (line 6) * vertical bar (|), || operator <1>: Precedence. (line 89) @@ -33980,7 +34060,7 @@ Index * | (vertical bar), | operator (I/O) <1>: Precedence. (line 65) * | (vertical bar), | operator (I/O) <2>: Redirection. (line 57) * | (vertical bar), | operator (I/O): Getline/Pipe. (line 9) -* | (vertical bar), |& operator (I/O) <1>: Two-way I/O. (line 44) +* | (vertical bar), |& operator (I/O) <1>: Two-way I/O. (line 25) * | (vertical bar), |& operator (I/O) <2>: Precedence. (line 65) * | (vertical bar), |& operator (I/O) <3>: Redirection. (line 102) * | (vertical bar), |& operator (I/O): Getline/Coprocess. (line 6) @@ -33993,8 +34073,8 @@ Index * ~ (tilde), ~ operator <3>: Comparison Operators. (line 11) * ~ (tilde), ~ operator <4>: Regexp Constants. (line 6) -* ~ (tilde), ~ operator <5>: Computed Regexps. (line 6) -* ~ (tilde), ~ operator <6>: Case-sensitivity. (line 26) +* ~ (tilde), ~ operator <5>: Case-sensitivity. (line 26) +* ~ (tilde), ~ operator <6>: Computed Regexps. (line 6) * ~ (tilde), ~ operator: Regexp Usage. (line 19) @@ -34003,550 +34083,551 @@ Tag Table: Node: Top1204 Node: Foreword41858 Node: Preface46203 -Ref: Preface-Footnote-149350 -Ref: Preface-Footnote-249457 -Node: History49689 -Node: Names52063 -Ref: Names-Footnote-153527 -Node: This Manual53600 -Ref: This Manual-Footnote-159379 -Node: Conventions59479 -Node: Manual History61635 -Ref: Manual History-Footnote-165074 -Ref: Manual History-Footnote-265115 -Node: How To Contribute65189 -Node: Acknowledgments66428 -Node: Getting Started70724 -Node: Running gawk73158 -Node: One-shot74348 -Node: Read Terminal75573 -Ref: Read Terminal-Footnote-177223 -Ref: Read Terminal-Footnote-277499 -Node: Long77670 -Node: Executable Scripts79046 -Ref: Executable Scripts-Footnote-180879 -Ref: Executable Scripts-Footnote-280981 -Node: Comments81528 -Node: Quoting84001 -Node: DOS Quoting89317 -Node: Sample Data Files89992 -Node: Very Simple92507 -Node: Two Rules97145 -Node: More Complex99039 -Ref: More Complex-Footnote-1101971 -Node: Statements/Lines102056 -Ref: Statements/Lines-Footnote-1106512 -Node: Other Features106777 -Node: When107705 -Node: Intro Summary109875 -Node: Invoking Gawk110641 -Node: Command Line112156 -Node: Options112947 -Ref: Options-Footnote-1128647 -Node: Other Arguments128672 -Node: Naming Standard Input131334 -Node: Environment Variables132428 -Node: AWKPATH Variable132986 -Ref: AWKPATH Variable-Footnote-1135858 -Ref: AWKPATH Variable-Footnote-2135903 -Node: AWKLIBPATH Variable136163 -Node: Other Environment Variables136922 -Node: Exit Status140372 -Node: Include Files141047 -Node: Loading Shared Libraries144625 -Node: Obsolete146009 -Node: Undocumented146706 -Node: Invoking Summary146973 -Node: Regexp148553 -Node: Regexp Usage150003 -Node: Escape Sequences152036 -Node: Regexp Operators157703 -Ref: Regexp Operators-Footnote-1165183 -Ref: Regexp Operators-Footnote-2165330 -Node: Bracket Expressions165428 -Ref: table-char-classes167318 -Node: GNU Regexp Operators170258 -Node: Case-sensitivity173981 -Ref: Case-sensitivity-Footnote-1176873 -Ref: Case-sensitivity-Footnote-2177108 -Node: Leftmost Longest177216 -Node: Computed Regexps178417 -Node: Regexp Summary181789 -Node: Reading Files183260 -Node: Records185352 -Node: awk split records186095 -Node: gawk split records190953 -Ref: gawk split records-Footnote-1195474 -Node: Fields195511 -Ref: Fields-Footnote-1198475 -Node: Nonconstant Fields198561 -Ref: Nonconstant Fields-Footnote-1200791 -Node: Changing Fields200993 -Node: Field Separators206947 -Node: Default Field Splitting209649 -Node: Regexp Field Splitting210766 -Node: Single Character Fields214107 -Node: Command Line Field Separator215166 -Node: Full Line Fields218508 -Ref: Full Line Fields-Footnote-1219016 -Node: Field Splitting Summary219062 -Ref: Field Splitting Summary-Footnote-1222161 -Node: Constant Size222262 -Node: Splitting By Content226869 -Ref: Splitting By Content-Footnote-1230619 -Node: Multiple Line230659 -Ref: Multiple Line-Footnote-1236515 -Node: Getline236694 -Node: Plain Getline238910 -Node: Getline/Variable241005 -Node: Getline/File242152 -Node: Getline/Variable/File243536 -Ref: Getline/Variable/File-Footnote-1245135 -Node: Getline/Pipe245222 -Node: Getline/Variable/Pipe247921 -Node: Getline/Coprocess249028 -Node: Getline/Variable/Coprocess250280 -Node: Getline Notes251017 -Node: Getline Summary253821 -Ref: table-getline-variants254229 -Node: Read Timeout255141 -Ref: Read Timeout-Footnote-1258968 -Node: Command line directories259026 -Node: Input Summary259930 -Node: Input Exercises263067 -Node: Printing263800 -Node: Print265522 -Node: Print Examples266863 -Node: Output Separators269642 -Node: OFMT271658 -Node: Printf273016 -Node: Basic Printf273922 -Node: Control Letters275461 -Node: Format Modifiers279452 -Node: Printf Examples285479 -Node: Redirection287943 -Node: Special Files294915 -Node: Special FD295446 -Ref: Special FD-Footnote-1299070 -Node: Special Network299144 -Node: Special Caveats299994 -Node: Close Files And Pipes300790 -Ref: Close Files And Pipes-Footnote-1307951 -Ref: Close Files And Pipes-Footnote-2308099 -Node: Output Summary308249 -Node: Output exercises309246 -Node: Expressions309926 -Node: Values311111 -Node: Constants311787 -Node: Scalar Constants312467 -Ref: Scalar Constants-Footnote-1313326 -Node: Nondecimal-numbers313576 -Node: Regexp Constants316576 -Node: Using Constant Regexps317051 -Node: Variables320121 -Node: Using Variables320776 -Node: Assignment Options322500 -Node: Conversion324375 -Node: Strings And Numbers324899 -Ref: Strings And Numbers-Footnote-1327961 -Node: Locale influences conversions328070 -Ref: table-locale-affects330787 -Node: All Operators331375 -Node: Arithmetic Ops332005 -Node: Concatenation334510 -Ref: Concatenation-Footnote-1337306 -Node: Assignment Ops337426 -Ref: table-assign-ops342409 -Node: Increment Ops343726 -Node: Truth Values and Conditions347164 -Node: Truth Values348247 -Node: Typing and Comparison349296 -Node: Variable Typing350089 -Ref: Variable Typing-Footnote-1353989 -Node: Comparison Operators354111 -Ref: table-relational-ops354521 -Node: POSIX String Comparison358071 -Ref: POSIX String Comparison-Footnote-1359155 -Node: Boolean Ops359293 -Ref: Boolean Ops-Footnote-1363363 -Node: Conditional Exp363454 -Node: Function Calls365181 -Node: Precedence369061 -Node: Locales372730 -Node: Expressions Summary374361 -Node: Patterns and Actions376902 -Node: Pattern Overview378018 -Node: Regexp Patterns379695 -Node: Expression Patterns380238 -Node: Ranges384019 -Node: BEGIN/END387125 -Node: Using BEGIN/END387887 -Ref: Using BEGIN/END-Footnote-1390623 -Node: I/O And BEGIN/END390729 -Node: BEGINFILE/ENDFILE393014 -Node: Empty395945 -Node: Using Shell Variables396262 -Node: Action Overview398545 -Node: Statements400872 -Node: If Statement402720 -Node: While Statement404218 -Node: Do Statement406262 -Node: For Statement407418 -Node: Switch Statement410570 -Node: Break Statement412673 -Node: Continue Statement414728 -Node: Next Statement416521 -Node: Nextfile Statement418911 -Node: Exit Statement421566 -Node: Built-in Variables423970 -Node: User-modified425097 -Ref: User-modified-Footnote-1432786 -Node: Auto-set432848 -Ref: Auto-set-Footnote-1445767 -Ref: Auto-set-Footnote-2445972 -Node: ARGC and ARGV446028 -Node: Pattern Action Summary449882 -Node: Arrays452105 -Node: Array Basics453654 -Node: Array Intro454480 -Ref: figure-array-elements456453 -Node: Reference to Elements458860 -Node: Assigning Elements461133 -Node: Array Example461624 -Node: Scanning an Array463356 -Node: Controlling Scanning466371 -Ref: Controlling Scanning-Footnote-1471544 -Node: Delete471860 -Ref: Delete-Footnote-1474625 -Node: Numeric Array Subscripts474682 -Node: Uninitialized Subscripts476865 -Node: Multidimensional478490 -Node: Multiscanning481583 -Node: Arrays of Arrays483172 -Node: Arrays Summary487835 -Node: Functions489940 -Node: Built-in490813 -Node: Calling Built-in491891 -Node: Numeric Functions493879 -Ref: Numeric Functions-Footnote-1498515 -Ref: Numeric Functions-Footnote-2498872 -Ref: Numeric Functions-Footnote-3498920 -Node: String Functions499189 -Ref: String Functions-Footnote-1522200 -Ref: String Functions-Footnote-2522329 -Ref: String Functions-Footnote-3522577 -Node: Gory Details522664 -Ref: table-sub-escapes524333 -Ref: table-sub-posix-92525687 -Ref: table-sub-proposed527038 -Ref: table-posix-sub528392 -Ref: table-gensub-escapes529937 -Ref: Gory Details-Footnote-1531113 -Ref: Gory Details-Footnote-2531164 -Node: I/O Functions531315 -Ref: I/O Functions-Footnote-1538438 -Node: Time Functions538585 -Ref: Time Functions-Footnote-1549049 -Ref: Time Functions-Footnote-2549117 -Ref: Time Functions-Footnote-3549275 -Ref: Time Functions-Footnote-4549386 -Ref: Time Functions-Footnote-5549498 -Ref: Time Functions-Footnote-6549725 -Node: Bitwise Functions549991 -Ref: table-bitwise-ops550553 -Ref: Bitwise Functions-Footnote-1554798 -Node: Type Functions554982 -Node: I18N Functions556124 -Node: User-defined557769 -Node: Definition Syntax558573 -Ref: Definition Syntax-Footnote-1563752 -Node: Function Example563821 -Ref: Function Example-Footnote-1566465 -Node: Function Caveats566487 -Node: Calling A Function567005 -Node: Variable Scope567960 -Node: Pass By Value/Reference570948 -Node: Return Statement574456 -Node: Dynamic Typing577440 -Node: Indirect Calls578369 -Node: Functions Summary588082 -Node: Library Functions590621 -Ref: Library Functions-Footnote-1594239 -Ref: Library Functions-Footnote-2594382 -Node: Library Names594553 -Ref: Library Names-Footnote-1598026 -Ref: Library Names-Footnote-2598246 -Node: General Functions598332 -Node: Strtonum Function599360 -Node: Assert Function602140 -Node: Round Function605466 -Node: Cliff Random Function607007 -Node: Ordinal Functions608023 -Ref: Ordinal Functions-Footnote-1611100 -Ref: Ordinal Functions-Footnote-2611352 -Node: Join Function611563 -Ref: Join Function-Footnote-1613334 -Node: Getlocaltime Function613534 -Node: Readfile Function617270 -Node: Data File Management619109 -Node: Filetrans Function619741 -Node: Rewind Function623810 -Node: File Checking625368 -Ref: File Checking-Footnote-1626500 -Node: Empty Files626701 -Node: Ignoring Assigns628680 -Node: Getopt Function630234 -Ref: Getopt Function-Footnote-1641537 -Node: Passwd Functions641740 -Ref: Passwd Functions-Footnote-1650719 -Node: Group Functions650807 -Ref: Group Functions-Footnote-1658748 -Node: Walking Arrays658961 -Node: Library Functions Summary660564 -Node: Library exercises661952 -Node: Sample Programs663232 -Node: Running Examples664002 -Node: Clones664730 -Node: Cut Program665954 -Node: Egrep Program675822 -Ref: Egrep Program-Footnote-1683793 -Node: Id Program683903 -Node: Split Program687567 -Ref: Split Program-Footnote-1691105 -Node: Tee Program691233 -Node: Uniq Program694040 -Node: Wc Program701470 -Ref: Wc Program-Footnote-1705735 -Node: Miscellaneous Programs705827 -Node: Dupword Program707040 -Node: Alarm Program709071 -Node: Translate Program713885 -Ref: Translate Program-Footnote-1718276 -Ref: Translate Program-Footnote-2718546 -Node: Labels Program718680 -Ref: Labels Program-Footnote-1722051 -Node: Word Sorting722135 -Node: History Sorting726178 -Node: Extract Program728014 -Node: Simple Sed735550 -Node: Igawk Program738612 -Ref: Igawk Program-Footnote-1752923 -Ref: Igawk Program-Footnote-2753124 -Node: Anagram Program753262 -Node: Signature Program756330 -Node: Programs Summary757577 -Node: Programs Exercises758792 -Node: Advanced Features762443 -Node: Nondecimal Data764391 -Node: Array Sorting765968 -Node: Controlling Array Traversal766665 -Node: Array Sorting Functions774945 -Ref: Array Sorting Functions-Footnote-1778852 -Node: Two-way I/O779046 -Ref: Two-way I/O-Footnote-1784562 -Node: TCP/IP Networking784644 -Node: Profiling787488 -Node: Advanced Features Summary795039 -Node: Internationalization796903 -Node: I18N and L10N798383 -Node: Explaining gettext799069 -Ref: Explaining gettext-Footnote-1804209 -Ref: Explaining gettext-Footnote-2804393 -Node: Programmer i18n804558 -Node: Translator i18n808783 -Node: String Extraction809577 -Ref: String Extraction-Footnote-1810538 -Node: Printf Ordering810624 -Ref: Printf Ordering-Footnote-1813406 -Node: I18N Portability813470 -Ref: I18N Portability-Footnote-1815919 -Node: I18N Example815982 -Ref: I18N Example-Footnote-1818704 -Node: Gawk I18N818776 -Node: I18N Summary819414 -Node: Debugger820753 -Node: Debugging821775 -Node: Debugging Concepts822216 -Node: Debugging Terms824072 -Node: Awk Debugging826669 -Node: Sample Debugging Session827561 -Node: Debugger Invocation828081 -Node: Finding The Bug829414 -Node: List of Debugger Commands835896 -Node: Breakpoint Control837228 -Node: Debugger Execution Control840892 -Node: Viewing And Changing Data844252 -Node: Execution Stack847610 -Node: Debugger Info849123 -Node: Miscellaneous Debugger Commands853117 -Node: Readline Support858301 -Node: Limitations859193 -Node: Debugging Summary861467 -Node: Arbitrary Precision Arithmetic862631 -Node: Computer Arithmetic863960 -Ref: Computer Arithmetic-Footnote-1868347 -Node: Math Definitions868404 -Ref: table-ieee-formats871288 -Node: MPFR features871792 -Node: FP Math Caution873434 -Ref: FP Math Caution-Footnote-1874475 -Node: Inexactness of computations874844 -Node: Inexact representation875792 -Node: Comparing FP Values877147 -Node: Errors accumulate878111 -Node: Getting Accuracy879544 -Node: Try To Round882203 -Node: Setting precision883102 -Ref: table-predefined-precision-strings883784 -Node: Setting the rounding mode885577 -Ref: table-gawk-rounding-modes885941 -Ref: Setting the rounding mode-Footnote-1889395 -Node: Arbitrary Precision Integers889574 -Ref: Arbitrary Precision Integers-Footnote-1893369 -Node: POSIX Floating Point Problems893518 -Ref: POSIX Floating Point Problems-Footnote-1897394 -Node: Floating point summary897432 -Node: Dynamic Extensions899649 -Node: Extension Intro901201 -Node: Plugin License902466 -Node: Extension Mechanism Outline903151 -Ref: figure-load-extension903575 -Ref: figure-load-new-function905060 -Ref: figure-call-new-function906062 -Node: Extension API Description908046 -Node: Extension API Functions Introduction909496 -Node: General Data Types914361 -Ref: General Data Types-Footnote-1920054 -Node: Requesting Values920353 -Ref: table-value-types-returned921090 -Node: Memory Allocation Functions922048 -Ref: Memory Allocation Functions-Footnote-1924795 -Node: Constructor Functions924891 -Node: Registration Functions926649 -Node: Extension Functions927334 -Node: Exit Callback Functions929636 -Node: Extension Version String930885 -Node: Input Parsers931535 -Node: Output Wrappers941349 -Node: Two-way processors945865 -Node: Printing Messages948069 -Ref: Printing Messages-Footnote-1949146 -Node: Updating `ERRNO'949298 -Node: Accessing Parameters950037 -Node: Symbol Table Access951267 -Node: Symbol table by name951781 -Node: Symbol table by cookie953757 -Ref: Symbol table by cookie-Footnote-1957890 -Node: Cached values957953 -Ref: Cached values-Footnote-1961457 -Node: Array Manipulation961548 -Ref: Array Manipulation-Footnote-1962646 -Node: Array Data Types962685 -Ref: Array Data Types-Footnote-1965388 -Node: Array Functions965480 -Node: Flattening Arrays969354 -Node: Creating Arrays976206 -Node: Extension API Variables980937 -Node: Extension Versioning981573 -Node: Extension API Informational Variables983474 -Node: Extension API Boilerplate984560 -Node: Finding Extensions988364 -Node: Extension Example988924 -Node: Internal File Description989654 -Node: Internal File Ops993745 -Ref: Internal File Ops-Footnote-11005177 -Node: Using Internal File Ops1005317 -Ref: Using Internal File Ops-Footnote-11007664 -Node: Extension Samples1007932 -Node: Extension Sample File Functions1009456 -Node: Extension Sample Fnmatch1017024 -Node: Extension Sample Fork1018506 -Node: Extension Sample Inplace1019719 -Node: Extension Sample Ord1021394 -Node: Extension Sample Readdir1022230 -Ref: table-readdir-file-types1023086 -Node: Extension Sample Revout1023885 -Node: Extension Sample Rev2way1024476 -Node: Extension Sample Read write array1025217 -Node: Extension Sample Readfile1027096 -Node: Extension Sample API Tests1028196 -Node: Extension Sample Time1028721 -Node: gawkextlib1030036 -Node: Extension summary1032849 -Node: Extension Exercises1036542 -Node: Language History1037264 -Node: V7/SVR3.11038907 -Node: SVR41041227 -Node: POSIX1042669 -Node: BTL1044055 -Node: POSIX/GNU1044789 -Node: Feature History1050532 -Node: Common Extensions1063662 -Node: Ranges and Locales1064974 -Ref: Ranges and Locales-Footnote-11069591 -Ref: Ranges and Locales-Footnote-21069618 -Ref: Ranges and Locales-Footnote-31069852 -Node: Contributors1070073 -Node: History summary1075498 -Node: Installation1076867 -Node: Gawk Distribution1077818 -Node: Getting1078302 -Node: Extracting1079126 -Node: Distribution contents1080768 -Node: Unix Installation1086538 -Node: Quick Installation1087155 -Node: Additional Configuration Options1089597 -Node: Configuration Philosophy1091335 -Node: Non-Unix Installation1093686 -Node: PC Installation1094144 -Node: PC Binary Installation1095455 -Node: PC Compiling1097303 -Ref: PC Compiling-Footnote-11100302 -Node: PC Testing1100407 -Node: PC Using1101583 -Node: Cygwin1105741 -Node: MSYS1106550 -Node: VMS Installation1107064 -Node: VMS Compilation1107860 -Ref: VMS Compilation-Footnote-11109082 -Node: VMS Dynamic Extensions1109140 -Node: VMS Installation Details1110513 -Node: VMS Running1112765 -Node: VMS GNV1115599 -Node: VMS Old Gawk1116322 -Node: Bugs1116792 -Node: Other Versions1120796 -Node: Installation summary1127051 -Node: Notes1128107 -Node: Compatibility Mode1128972 -Node: Additions1129754 -Node: Accessing The Source1130679 -Node: Adding Code1132115 -Node: New Ports1138293 -Node: Derived Files1142774 -Ref: Derived Files-Footnote-11147855 -Ref: Derived Files-Footnote-21147889 -Ref: Derived Files-Footnote-31148485 -Node: Future Extensions1148599 -Node: Implementation Limitations1149205 -Node: Extension Design1150453 -Node: Old Extension Problems1151607 -Ref: Old Extension Problems-Footnote-11153124 -Node: Extension New Mechanism Goals1153181 -Ref: Extension New Mechanism Goals-Footnote-11156541 -Node: Extension Other Design Decisions1156730 -Node: Extension Future Growth1158836 -Node: Old Extension Mechanism1159672 -Node: Notes summary1161434 -Node: Basic Concepts1162620 -Node: Basic High Level1163301 -Ref: figure-general-flow1163573 -Ref: figure-process-flow1164172 -Ref: Basic High Level-Footnote-11167401 -Node: Basic Data Typing1167586 -Node: Glossary1170914 -Node: Copying1196066 -Node: GNU Free Documentation License1233622 -Node: Index1258758 +Ref: Preface-Footnote-149226 +Ref: Preface-Footnote-249333 +Node: History49565 +Node: Names51939 +Ref: Names-Footnote-153033 +Node: This Manual53179 +Ref: This Manual-Footnote-158958 +Node: Conventions59058 +Node: Manual History61403 +Ref: Manual History-Footnote-164479 +Ref: Manual History-Footnote-264520 +Node: How To Contribute64594 +Node: Acknowledgments65833 +Node: Getting Started70581 +Node: Running gawk73015 +Node: One-shot74205 +Node: Read Terminal75430 +Node: Long77455 +Node: Executable Scripts78849 +Ref: Executable Scripts-Footnote-181650 +Node: Comments81752 +Node: Quoting84225 +Node: DOS Quoting89538 +Node: Sample Data Files90213 +Node: Very Simple92820 +Node: Two Rules97705 +Node: More Complex99599 +Ref: More Complex-Footnote-1102513 +Node: Statements/Lines102598 +Ref: Statements/Lines-Footnote-1107054 +Node: Other Features107319 +Node: When108250 +Ref: When-Footnote-1110006 +Node: Intro Summary110071 +Node: Invoking Gawk110954 +Node: Command Line112469 +Node: Options113260 +Ref: Options-Footnote-1128907 +Node: Other Arguments128932 +Node: Naming Standard Input131760 +Node: Environment Variables132853 +Node: AWKPATH Variable133411 +Ref: AWKPATH Variable-Footnote-1136277 +Ref: AWKPATH Variable-Footnote-2136322 +Node: AWKLIBPATH Variable136582 +Node: Other Environment Variables137341 +Node: Exit Status140793 +Node: Include Files141468 +Node: Loading Shared Libraries145046 +Node: Obsolete146430 +Node: Undocumented147127 +Node: Invoking Summary147394 +Node: Regexp148994 +Node: Regexp Usage150453 +Node: Escape Sequences152486 +Node: Regexp Operators158557 +Ref: Regexp Operators-Footnote-1165988 +Ref: Regexp Operators-Footnote-2166135 +Node: Bracket Expressions166233 +Ref: table-char-classes168251 +Node: Leftmost Longest171191 +Node: Computed Regexps172395 +Node: GNU Regexp Operators175773 +Node: Case-sensitivity179479 +Ref: Case-sensitivity-Footnote-1182369 +Ref: Case-sensitivity-Footnote-2182604 +Node: Regexp Summary182712 +Node: Reading Files184181 +Node: Records186273 +Node: awk split records186995 +Node: gawk split records191853 +Ref: gawk split records-Footnote-1196374 +Node: Fields196411 +Ref: Fields-Footnote-1199375 +Node: Nonconstant Fields199461 +Ref: Nonconstant Fields-Footnote-1201691 +Node: Changing Fields201893 +Node: Field Separators207847 +Node: Default Field Splitting210549 +Node: Regexp Field Splitting211666 +Node: Single Character Fields214993 +Node: Command Line Field Separator216052 +Node: Full Line Fields219478 +Ref: Full Line Fields-Footnote-1219986 +Node: Field Splitting Summary220032 +Ref: Field Splitting Summary-Footnote-1223164 +Node: Constant Size223265 +Node: Splitting By Content227871 +Ref: Splitting By Content-Footnote-1231944 +Node: Multiple Line231984 +Ref: Multiple Line-Footnote-1237840 +Node: Getline238019 +Node: Plain Getline240230 +Node: Getline/Variable242936 +Node: Getline/File244083 +Node: Getline/Variable/File245467 +Ref: Getline/Variable/File-Footnote-1247066 +Node: Getline/Pipe247153 +Node: Getline/Variable/Pipe249839 +Node: Getline/Coprocess250946 +Node: Getline/Variable/Coprocess252198 +Node: Getline Notes252935 +Node: Getline Summary255739 +Ref: table-getline-variants256147 +Node: Read Timeout257059 +Ref: Read Timeout-Footnote-1260886 +Node: Command-line directories260944 +Node: Input Summary261848 +Node: Input Exercises264985 +Node: Printing265713 +Node: Print267435 +Node: Print Examples268928 +Node: Output Separators271707 +Node: OFMT273723 +Node: Printf275081 +Node: Basic Printf275987 +Node: Control Letters277526 +Node: Format Modifiers281517 +Node: Printf Examples287544 +Node: Redirection290008 +Node: Special Files296980 +Node: Special FD297513 +Ref: Special FD-Footnote-1301110 +Node: Special Network301184 +Node: Special Caveats302034 +Node: Close Files And Pipes302830 +Ref: Close Files And Pipes-Footnote-1309991 +Ref: Close Files And Pipes-Footnote-2310139 +Node: Output Summary310289 +Node: Output Exercises311286 +Node: Expressions311966 +Node: Values313151 +Node: Constants313827 +Node: Scalar Constants314507 +Ref: Scalar Constants-Footnote-1315366 +Node: Nondecimal-numbers315616 +Node: Regexp Constants318616 +Node: Using Constant Regexps319141 +Node: Variables322213 +Node: Using Variables322868 +Node: Assignment Options324592 +Node: Conversion326467 +Node: Strings And Numbers326991 +Ref: Strings And Numbers-Footnote-1330053 +Node: Locale influences conversions330162 +Ref: table-locale-affects332879 +Node: All Operators333467 +Node: Arithmetic Ops334097 +Node: Concatenation336602 +Ref: Concatenation-Footnote-1339421 +Node: Assignment Ops339527 +Ref: table-assign-ops344510 +Node: Increment Ops345813 +Node: Truth Values and Conditions349251 +Node: Truth Values350334 +Node: Typing and Comparison351383 +Node: Variable Typing352176 +Node: Comparison Operators355828 +Ref: table-relational-ops356238 +Node: POSIX String Comparison359788 +Ref: POSIX String Comparison-Footnote-1360872 +Node: Boolean Ops361010 +Ref: Boolean Ops-Footnote-1365349 +Node: Conditional Exp365440 +Node: Function Calls367167 +Node: Precedence371047 +Node: Locales374716 +Node: Expressions Summary376347 +Node: Patterns and Actions378888 +Node: Pattern Overview380004 +Node: Regexp Patterns381681 +Node: Expression Patterns382224 +Node: Ranges386004 +Node: BEGIN/END389110 +Node: Using BEGIN/END389872 +Ref: Using BEGIN/END-Footnote-1392608 +Node: I/O And BEGIN/END392714 +Node: BEGINFILE/ENDFILE394985 +Node: Empty397916 +Node: Using Shell Variables398233 +Node: Action Overview400516 +Node: Statements402843 +Node: If Statement404691 +Node: While Statement406189 +Node: Do Statement408233 +Node: For Statement409389 +Node: Switch Statement412541 +Node: Break Statement414929 +Node: Continue Statement416970 +Node: Next Statement418795 +Node: Nextfile Statement421185 +Node: Exit Statement423842 +Node: Built-in Variables426246 +Node: User-modified427373 +Ref: User-modified-Footnote-1435062 +Node: Auto-set435124 +Ref: Auto-set-Footnote-1448143 +Ref: Auto-set-Footnote-2448348 +Node: ARGC and ARGV448404 +Node: Pattern Action Summary452308 +Node: Arrays454531 +Node: Array Basics456080 +Node: Array Intro456906 +Ref: figure-array-elements458879 +Ref: Array Intro-Footnote-1461403 +Node: Reference to Elements461531 +Node: Assigning Elements463981 +Node: Array Example464472 +Node: Scanning an Array466204 +Node: Controlling Scanning469205 +Ref: Controlling Scanning-Footnote-1474378 +Node: Delete474694 +Ref: Delete-Footnote-1477445 +Node: Numeric Array Subscripts477502 +Node: Uninitialized Subscripts479685 +Node: Multidimensional481312 +Node: Multiscanning484425 +Node: Arrays of Arrays486014 +Node: Arrays Summary490677 +Node: Functions492782 +Node: Built-in493655 +Node: Calling Built-in494733 +Node: Numeric Functions496721 +Ref: Numeric Functions-Footnote-1501557 +Ref: Numeric Functions-Footnote-2501914 +Ref: Numeric Functions-Footnote-3501962 +Node: String Functions502231 +Ref: String Functions-Footnote-1525228 +Ref: String Functions-Footnote-2525357 +Ref: String Functions-Footnote-3525605 +Node: Gory Details525692 +Ref: table-sub-escapes527465 +Ref: table-sub-proposed528985 +Ref: table-posix-sub530349 +Ref: table-gensub-escapes531889 +Ref: Gory Details-Footnote-1533065 +Node: I/O Functions533216 +Ref: I/O Functions-Footnote-1540326 +Node: Time Functions540473 +Ref: Time Functions-Footnote-1550937 +Ref: Time Functions-Footnote-2551005 +Ref: Time Functions-Footnote-3551163 +Ref: Time Functions-Footnote-4551274 +Ref: Time Functions-Footnote-5551386 +Ref: Time Functions-Footnote-6551613 +Node: Bitwise Functions551879 +Ref: table-bitwise-ops552441 +Ref: Bitwise Functions-Footnote-1556686 +Node: Type Functions556870 +Node: I18N Functions558012 +Node: User-defined559657 +Node: Definition Syntax560461 +Ref: Definition Syntax-Footnote-1565774 +Node: Function Example565843 +Ref: Function Example-Footnote-1568483 +Node: Function Caveats568505 +Node: Calling A Function569023 +Node: Variable Scope569978 +Node: Pass By Value/Reference572966 +Node: Return Statement576476 +Node: Dynamic Typing579460 +Node: Indirect Calls580389 +Ref: Indirect Calls-Footnote-1590105 +Node: Functions Summary590233 +Node: Library Functions592883 +Ref: Library Functions-Footnote-1596501 +Ref: Library Functions-Footnote-2596644 +Node: Library Names596815 +Ref: Library Names-Footnote-1600288 +Ref: Library Names-Footnote-2600508 +Node: General Functions600594 +Node: Strtonum Function601622 +Node: Assert Function604496 +Node: Round Function607822 +Node: Cliff Random Function609363 +Node: Ordinal Functions610379 +Ref: Ordinal Functions-Footnote-1613444 +Ref: Ordinal Functions-Footnote-2613696 +Node: Join Function613907 +Ref: Join Function-Footnote-1615678 +Node: Getlocaltime Function615878 +Node: Readfile Function619614 +Node: Data File Management621453 +Node: Filetrans Function622085 +Node: Rewind Function626154 +Node: File Checking627712 +Ref: File Checking-Footnote-1628844 +Node: Empty Files629045 +Node: Ignoring Assigns631024 +Node: Getopt Function632578 +Ref: Getopt Function-Footnote-1643842 +Node: Passwd Functions644045 +Ref: Passwd Functions-Footnote-1653024 +Node: Group Functions653112 +Ref: Group Functions-Footnote-1661043 +Node: Walking Arrays661256 +Node: Library Functions Summary662859 +Node: Library Exercises664247 +Node: Sample Programs665527 +Node: Running Examples666297 +Node: Clones667025 +Node: Cut Program668249 +Node: Egrep Program678107 +Ref: Egrep Program-Footnote-1685694 +Node: Id Program685804 +Node: Split Program689458 +Ref: Split Program-Footnote-1692996 +Node: Tee Program693124 +Node: Uniq Program695911 +Node: Wc Program703334 +Ref: Wc Program-Footnote-1707599 +Node: Miscellaneous Programs707691 +Node: Dupword Program708904 +Node: Alarm Program710935 +Node: Translate Program715739 +Ref: Translate Program-Footnote-1720312 +Ref: Translate Program-Footnote-2720582 +Node: Labels Program720721 +Ref: Labels Program-Footnote-1724082 +Node: Word Sorting724166 +Node: History Sorting728209 +Node: Extract Program730045 +Node: Simple Sed737581 +Node: Igawk Program740643 +Ref: Igawk Program-Footnote-1754947 +Ref: Igawk Program-Footnote-2755148 +Node: Anagram Program755286 +Node: Signature Program758354 +Node: Programs Summary759601 +Node: Programs Exercises760816 +Ref: Programs Exercises-Footnote-1764947 +Node: Advanced Features765038 +Node: Nondecimal Data766986 +Node: Array Sorting768563 +Node: Controlling Array Traversal769260 +Node: Array Sorting Functions777540 +Ref: Array Sorting Functions-Footnote-1781447 +Node: Two-way I/O781641 +Ref: Two-way I/O-Footnote-1786585 +Ref: Two-way I/O-Footnote-2786764 +Node: TCP/IP Networking786846 +Node: Profiling789691 +Node: Advanced Features Summary797242 +Node: Internationalization799106 +Node: I18N and L10N800586 +Node: Explaining gettext801272 +Ref: Explaining gettext-Footnote-1806298 +Ref: Explaining gettext-Footnote-2806482 +Node: Programmer i18n806647 +Ref: Programmer i18n-Footnote-1811441 +Node: Translator i18n811490 +Node: String Extraction812284 +Ref: String Extraction-Footnote-1813417 +Node: Printf Ordering813503 +Ref: Printf Ordering-Footnote-1816285 +Node: I18N Portability816349 +Ref: I18N Portability-Footnote-1818798 +Node: I18N Example818861 +Ref: I18N Example-Footnote-1821567 +Node: Gawk I18N821639 +Node: I18N Summary822277 +Node: Debugger823616 +Node: Debugging824638 +Node: Debugging Concepts825079 +Node: Debugging Terms826935 +Node: Awk Debugging829532 +Node: Sample Debugging Session830424 +Node: Debugger Invocation830944 +Node: Finding The Bug832280 +Node: List of Debugger Commands838759 +Node: Breakpoint Control840091 +Node: Debugger Execution Control843755 +Node: Viewing And Changing Data847115 +Node: Execution Stack850473 +Node: Debugger Info851986 +Node: Miscellaneous Debugger Commands855980 +Node: Readline Support861164 +Node: Limitations862056 +Node: Debugging Summary864329 +Node: Arbitrary Precision Arithmetic865497 +Node: Computer Arithmetic866984 +Ref: Computer Arithmetic-Footnote-1871371 +Node: Math Definitions871428 +Ref: table-ieee-formats874717 +Ref: Math Definitions-Footnote-1875257 +Node: MPFR features875360 +Node: FP Math Caution876977 +Ref: FP Math Caution-Footnote-1878027 +Node: Inexactness of computations878396 +Node: Inexact representation879344 +Node: Comparing FP Values880699 +Node: Errors accumulate881663 +Node: Getting Accuracy883096 +Node: Try To Round885755 +Node: Setting precision886654 +Ref: table-predefined-precision-strings887336 +Node: Setting the rounding mode889129 +Ref: table-gawk-rounding-modes889493 +Ref: Setting the rounding mode-Footnote-1892947 +Node: Arbitrary Precision Integers893126 +Ref: Arbitrary Precision Integers-Footnote-1896899 +Node: POSIX Floating Point Problems897048 +Ref: POSIX Floating Point Problems-Footnote-1900924 +Node: Floating point summary900962 +Node: Dynamic Extensions903166 +Node: Extension Intro904718 +Node: Plugin License905983 +Node: Extension Mechanism Outline906668 +Ref: figure-load-extension907092 +Ref: figure-load-new-function908577 +Ref: figure-call-new-function909579 +Node: Extension API Description911563 +Node: Extension API Functions Introduction913013 +Node: General Data Types917880 +Ref: General Data Types-Footnote-1923573 +Node: Requesting Values923872 +Ref: table-value-types-returned924609 +Node: Memory Allocation Functions925567 +Ref: Memory Allocation Functions-Footnote-1928314 +Node: Constructor Functions928410 +Node: Registration Functions930168 +Node: Extension Functions930853 +Node: Exit Callback Functions933155 +Node: Extension Version String934403 +Node: Input Parsers935053 +Node: Output Wrappers944867 +Node: Two-way processors949383 +Node: Printing Messages951587 +Ref: Printing Messages-Footnote-1952664 +Node: Updating `ERRNO'952816 +Node: Accessing Parameters953555 +Node: Symbol Table Access954785 +Node: Symbol table by name955299 +Node: Symbol table by cookie957275 +Ref: Symbol table by cookie-Footnote-1961408 +Node: Cached values961471 +Ref: Cached values-Footnote-1964975 +Node: Array Manipulation965066 +Ref: Array Manipulation-Footnote-1966164 +Node: Array Data Types966203 +Ref: Array Data Types-Footnote-1968906 +Node: Array Functions968998 +Node: Flattening Arrays972872 +Node: Creating Arrays979724 +Node: Extension API Variables984455 +Node: Extension Versioning985091 +Node: Extension API Informational Variables986992 +Node: Extension API Boilerplate988078 +Node: Finding Extensions991882 +Node: Extension Example992442 +Node: Internal File Description993172 +Node: Internal File Ops997263 +Ref: Internal File Ops-Footnote-11008695 +Node: Using Internal File Ops1008835 +Ref: Using Internal File Ops-Footnote-11011182 +Node: Extension Samples1011450 +Node: Extension Sample File Functions1012974 +Node: Extension Sample Fnmatch1020542 +Node: Extension Sample Fork1022024 +Node: Extension Sample Inplace1023237 +Node: Extension Sample Ord1024912 +Node: Extension Sample Readdir1025748 +Ref: table-readdir-file-types1026604 +Node: Extension Sample Revout1027403 +Node: Extension Sample Rev2way1027994 +Node: Extension Sample Read write array1028735 +Node: Extension Sample Readfile1030614 +Node: Extension Sample API Tests1031714 +Node: Extension Sample Time1032239 +Node: gawkextlib1033554 +Node: Extension summary1036367 +Node: Extension Exercises1040060 +Node: Language History1040782 +Node: V7/SVR3.11042425 +Node: SVR41044745 +Node: POSIX1046187 +Node: BTL1047573 +Node: POSIX/GNU1048307 +Node: Feature History1054083 +Node: Common Extensions1067174 +Node: Ranges and Locales1068486 +Ref: Ranges and Locales-Footnote-11073103 +Ref: Ranges and Locales-Footnote-21073130 +Ref: Ranges and Locales-Footnote-31073364 +Node: Contributors1073585 +Node: History summary1079010 +Node: Installation1080379 +Node: Gawk Distribution1081330 +Node: Getting1081814 +Node: Extracting1082638 +Node: Distribution contents1084280 +Node: Unix Installation1090050 +Node: Quick Installation1090667 +Node: Additional Configuration Options1093109 +Node: Configuration Philosophy1094847 +Node: Non-Unix Installation1097198 +Node: PC Installation1097656 +Node: PC Binary Installation1098967 +Node: PC Compiling1100815 +Ref: PC Compiling-Footnote-11103814 +Node: PC Testing1103919 +Node: PC Using1105095 +Node: Cygwin1109247 +Node: MSYS1110056 +Node: VMS Installation1110570 +Node: VMS Compilation1111366 +Ref: VMS Compilation-Footnote-11112588 +Node: VMS Dynamic Extensions1112646 +Node: VMS Installation Details1114019 +Node: VMS Running1116271 +Node: VMS GNV1119105 +Node: VMS Old Gawk1119828 +Node: Bugs1120298 +Node: Other Versions1124302 +Node: Installation summary1130529 +Node: Notes1131585 +Node: Compatibility Mode1132450 +Node: Additions1133232 +Node: Accessing The Source1134157 +Node: Adding Code1135593 +Node: New Ports1141771 +Node: Derived Files1146252 +Ref: Derived Files-Footnote-11151333 +Ref: Derived Files-Footnote-21151367 +Ref: Derived Files-Footnote-31151963 +Node: Future Extensions1152077 +Node: Implementation Limitations1152683 +Node: Extension Design1153931 +Node: Old Extension Problems1155085 +Ref: Old Extension Problems-Footnote-11156602 +Node: Extension New Mechanism Goals1156659 +Ref: Extension New Mechanism Goals-Footnote-11160019 +Node: Extension Other Design Decisions1160208 +Node: Extension Future Growth1162314 +Node: Old Extension Mechanism1163150 +Node: Notes summary1164912 +Node: Basic Concepts1166098 +Node: Basic High Level1166779 +Ref: figure-general-flow1167051 +Ref: figure-process-flow1167650 +Ref: Basic High Level-Footnote-11170879 +Node: Basic Data Typing1171064 +Node: Glossary1174392 +Node: Copying1199544 +Node: GNU Free Documentation License1237100 +Node: Index1262236 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 6bbc6562..a809bd0d 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -51,7 +51,7 @@ @c applies to and all the info about who's publishing this edition @c These apply across the board. -@set UPDATE-MONTH July, 2014 +@set UPDATE-MONTH August, 2014 @set VERSION 4.1 @set PATCHLEVEL 1 @@ -165,6 +165,19 @@ @end macro @end ifdocbook +@c hack for docbook, where comma shouldn't always follow an @ref{} +@ifdocbook +@macro DBREF{text} +@ref{\text\} +@end macro +@end ifdocbook + +@ifnotdocbook +@macro DBREF{text} +@ref{\text\}, +@end macro +@end ifnotdocbook + @ifclear FOR_PRINT @set FN file name @set FFN File Name @@ -526,10 +539,10 @@ particular records in a file and perform operations upon them. * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between @samp{[...]}. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. * Records:: Controlling how data is split into records. @@ -546,7 +559,7 @@ particular records in a file and perform operations upon them. * Single Character Fields:: Making each character a separate field. * Command Line Field Separator:: Setting @code{FS} from the - command-line. + command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -572,7 +585,7 @@ particular records in a file and perform operations upon them. @code{getline}. * Getline Summary:: Summary of @code{getline} Variants. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -600,7 +613,7 @@ particular records in a file and perform operations upon them. * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. * Values:: Constants, Variables, and Regular Expressions. * Constants:: String, numeric and regexp constants. @@ -611,7 +624,7 @@ particular records in a file and perform operations upon them. * Variables:: Variables give names to values for later use. * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. * Conversion:: The conversion of strings to numbers @@ -787,7 +800,7 @@ particular records in a file and perform operations upon them. information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. * Running Examples:: How to run these examples. * Clones:: Clones of common utilities. * Cut Program:: The @command{cut} utility. @@ -1211,23 +1224,18 @@ March, 2001 </prefaceinfo> @end docbook -Several kinds of tasks occur repeatedly -when working with text files. -You might want to extract certain lines and discard the rest. -Or you may need to make changes wherever certain patterns appear, -but leave the rest of the file alone. -Writing single-use programs for these tasks in languages such as C, C++, -or Java is time-consuming and inconvenient. -Such jobs are often easier with @command{awk}. -The @command{awk} utility interprets a special-purpose programming language -that makes it easy to handle simple data-reformatting jobs. +Several kinds of tasks occur repeatedly when working with text files. +You might want to extract certain lines and discard the rest. Or you +may need to make changes wherever certain patterns appear, but leave the +rest of the file alone. Such jobs are often easy with @command{awk}. +The @command{awk} utility interprets a special-purpose programming +language that makes it easy to handle simple data-reformatting jobs. -@cindex Brian Kernighan's @command{awk} The GNU implementation of @command{awk} is called @command{gawk}; if you invoke it with the proper options or environment variables (@pxref{Options}), it is fully compatible with -the POSIX@footnote{The 2008 POSIX standard is accessable online at +the POSIX@footnote{The 2008 POSIX standard is accessible online at @w{@url{http://www.opengroup.org/onlinepubs/9699919799/}.}} specification of the @command{awk} language and with the Unix version of @command{awk} maintained @@ -1301,7 +1309,7 @@ different computing environments. This @value{DOCUMENT}, while describing the @command{awk} language in general, also describes the particular implementation of @command{awk} called @command{gawk} (which stands for ``GNU @command{awk}''). @command{gawk} runs on a broad range of Unix systems, -ranging from Intel@registeredsymbol{}-architecture PC-based computers +ranging from Intel-architecture PC-based computers up through large-scale systems. @command{gawk} has also been ported to Mac OS X, Microsoft Windows @@ -1404,7 +1412,7 @@ help from me, thoroughly reworked @command{gawk} for compatibility with the newer @command{awk}. Circa 1994, I became the primary maintainer. Current development focuses on bug fixes, -performance improvements, standards compliance, and occasionally, new features. +performance improvements, standards compliance and, occasionally, new features. In May of 1997, J@"urgen Kahrs felt the need for network access from @command{awk}, and with a little help from me, set about adding @@ -1429,29 +1437,27 @@ for a complete list of those who made important contributions to @command{gawk}. The @command{awk} language has evolved over the years. Full details are provided in @ref{Language History}. The language described in this @value{DOCUMENT} -is often referred to as ``new @command{awk}'' (@command{nawk}). +is often referred to as ``new @command{awk}''. +By analogy, the original version of @command{awk} is +referred to as ``old @command{awk}.'' -@cindex @command{awk}, versions of -@cindex @command{nawk} utility -@cindex @command{oawk} utility -For some time after new @command{awk} was introduced, there were -systems with multiple versions of @command{awk}. Some systems had -an @command{awk} utility that implemented the original version of the -@command{awk} language and a @command{nawk} utility for the new version. -Others had an @command{oawk} version for the ``old @command{awk}'' -language and plain @command{awk} for the new one. Still others only -had one version, which is usually the new one. - -Today, only Solaris systems still use an old @command{awk} for the -default @command{awk} utility. (A more modern @command{awk} lives in -@file{/usr/xpg6/bin} on these systems.) All other modern systems use -some version of new @command{awk}.@footnote{Many of these systems use -@command{gawk} for their @command{awk} implementation!} - -It is likely that you already have some version of new @command{awk} on -your system, which is what you should use when running your programs. -(Of course, if you're reading this @value{DOCUMENT}, chances are good -that you have @command{gawk}!) +Today, on most systems, when you run the @command{awk} utility, +you get some version of new @command{awk}.@footnote{Only +Solaris systems still use an old @command{awk} for the +default @command{awk} utility. A more modern @command{awk} lives in +@file{/usr/xpg6/bin} on these systems.} If your system's standard +@command{awk} is the old one, you will see something like this +if you try the test program: + +@example +$ @kbd{awk 1 /dev/null} +@error{} awk: syntax error near line 1 +@error{} awk: bailing out near line 1 +@end example + +@noindent +In this case, you should find a version of new @command{awk}, +or just install @command{gawk}! Throughout this @value{DOCUMENT}, whenever we refer to a language feature that should be available in any complete implementation of POSIX @command{awk}, @@ -1502,7 +1508,9 @@ There are sidebars scattered throughout the @value{DOCUMENT}. They add a more complete explanation of points that are relevant, but not likely to be of interest on first reading. +@ifclear FOR_PRINT All appear in the index, under the heading ``sidebar.'' +@end ifclear Most of the time, the examples use complete @command{awk} programs. Some of the more advanced sections show only the part of the @command{awk} @@ -1657,6 +1665,9 @@ try looking them up here. @uref{http://www.gnu.org/software/gawk/manual/html_node/GNU-Free-Documentation-License.html, The GNU FDL} is the license that covers this @value{DOCUMENT}. + +Some of the chapters have exercise sections; these have also been +omitted from the print edition. @end ifset @ifclear FOR_PRINT @@ -1697,11 +1708,18 @@ are slightly different than in other books you may have read. This @value{SECTION} briefly documents the typographical conventions used in Texinfo. @end ifinfo -Examples you would type at the command-line are preceded by the common +Examples you would type at the command line are preceded by the common shell primary and secondary prompts, @samp{$} and @samp{>}. Input that you type is shown @kbd{like this}. +@c 8/2014: @print{} is stripped from the texi to make docbook. +@ifclear FOR_PRINT Output from the command is preceded by the glyph ``@print{}''. This typically represents the command's standard output. +@end ifclear +@ifset FOR_PRINT +Output from the command, usually its standard output, appears +@code{like this}. +@end ifset Error messages, and other output on the command's standard error, are preceded by the glyph ``@error{}''. For example: @@ -1731,6 +1749,10 @@ another key, at the same time. For example, a @kbd{Ctrl-d} is typed by first pressing and holding the @kbd{CONTROL} key, next pressing the @kbd{d} key and finally releasing both keys. +For the sake of brevity, throughout this @value{DOCUMENT}, we refer to +Brian Kernighan's version of @command{awk} as ``BWK @command{awk}.'' +(@xref{Other Versions}, for information on his and other versions.) + @ifset FOR_PRINT @quotation NOTE Notes of interest look like this. @@ -1770,6 +1792,7 @@ They also appear in the index under the heading ``dark corner.'' As noted by the opening quote, though, any coverage of dark corners is, by definition, incomplete. +@cindex c.e., See common extensions Extensions to the standard @command{awk} language that are supported by more than one @command{awk} implementation are marked @ifclear FOR_PRINT @@ -1777,7 +1800,7 @@ more than one @command{awk} implementation are marked and ``extensions, common.'' @end ifclear @ifset FOR_PRINT -``@value{COMMONEXT}.'' +``@value{COMMONEXT}'' for ``common extension.'' @end ifset @node Manual History @@ -1816,6 +1839,7 @@ see @uref{http://www.gnu.org, the GNU Project's home page}. This @value{DOCUMENT} may also be read from @uref{http://www.gnu.org/software/gawk/manual/, their web site}. +@ifclear FOR_PRINT A shell, an editor (Emacs), highly portable optimizing C, C++, and Objective-C compilers, a symbolic debugger and dozens of large and small utilities (such as @command{gawk}), have all been completed and are @@ -1826,32 +1850,16 @@ stage of development. @cindex Linux @cindex GNU/Linux @cindex operating systems, BSD-based -@cindex Alpha (DEC) Until the GNU operating system is more fully developed, you should consider using GNU/Linux, a freely distributable, Unix-like operating -system for Intel@registeredsymbol{}, +system for Intel, Power Architecture, Sun SPARC, IBM S/390, and other -@ifclear FOR_PRINT systems.@footnote{The terminology ``GNU/Linux'' is explained in the @ref{Glossary}.} -@end ifclear -@ifset FOR_PRINT -systems. -@end ifset Many GNU/Linux distributions are available for download from the Internet. - -(There are numerous other freely available, Unix-like operating systems -based on the -Berkeley Software Distribution, and some of them use recent versions -of @command{gawk} for their versions of @command{awk}. -@uref{http://www.netbsd.org, NetBSD}, -@uref{http://www.freebsd.org, FreeBSD}, -and -@uref{http://www.openbsd.org, OpenBSD} -are three of the most popular ones, but there -are others.) +@end ifclear @ifnotinfo The @value{DOCUMENT} you are reading is actually free---at least, the @@ -2095,17 +2103,29 @@ people. Notable code and documentation contributions were made by a number of people. @xref{Contributors}, for the full list. -Thanks to Patrice Dumas for the new @command{makeinfo} program. +Thanks to Patrice Dumas for the new @command{makeinfo} program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. @cindex Kernighan, Brian +@cindex Brennan, Michael +@cindex Day, Robert P.J.@: +Robert P.J.@: Day, Michael Brennan and Brian Kernighan kindly acted as +reviewers for the 2015 edition of this @value{DOCUMENT}. Their feedback +helped improve the final work. + I would like to thank Brian Kernighan for invaluable assistance during the testing and debugging of @command{gawk}, and for ongoing help and advice in clarifying numerous points about the language. We could not have done nearly as good a job on either @command{gawk} or its documentation without his help. +Brian is in a class by himself as a programmer and technical +author. I have to thank him (yet again) for his ongoing friendship +and the role model he has been for me for close to 30 years! +Having him as a reviewer is an exciting privilege. It has also +been extremely humbling@enddots{} + @cindex Robbins, Miriam @cindex Robbins, Jean @cindex Robbins, Harry @@ -2340,29 +2360,27 @@ For example, on OS/2, it is @kbd{Ctrl-z}.) As an example, the following program prints a friendly piece of advice (from Douglas Adams's @cite{The Hitchhiker's Guide to the Galaxy}), to keep you from worrying about the complexities of computer -programming@footnote{If you use Bash as your shell, you should execute -the command @samp{set +H} before running this program interactively, -to disable the C shell-style command history, which treats -@samp{!} as a special character. We recommend putting this command into -your personal startup file.} -(@code{BEGIN} is a feature we haven't discussed yet): +programming: @example -$ @kbd{awk "BEGIN @{ print \"Don't Panic!\" @}"} +$ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} @print{} Don't Panic! @end example -@cindex shell quoting, double quote -@cindex double quote (@code{"}) in shell commands -@cindex @code{"} (double quote) in shell commands -@cindex @code{\} (backslash) in shell commands -@cindex backslash (@code{\}) in shell commands -This program does not read any input. The @samp{\} before each of the -inner double quotes is necessary because of the shell's quoting -rules---in particular because it mixes both single quotes and -double quotes.@footnote{Although we generally recommend the use of single -quotes around the program text, double quotes are needed here in order to -put the single quote into the message.} +@command{awk} executes statements associated with @code{BEGIN} before +reading any input. If there are no other statements in your program, +as is the case here, @command{awk} just stops, instead of trying to read +input it doesn't know how to process. +The @samp{\47} is a magic way of getting a single quote into +the program, without having to engage in ugly shell quoting tricks. + +@quotation NOTE +As a side note, if you use Bash as your shell, you should execute the +command @samp{set +H} before running this program interactively, to +disable the C shell-style command history, which treats @samp{!} as a +special character. We recommend putting this command into your personal +startup file. +@end quotation This next simple @command{awk} program emulates the @command{cat} utility; it copies whatever you type on the @@ -2397,9 +2415,10 @@ awk -f @var{source-file} @var{input-file1} @var{input-file2} @dots{} @cindex @option{-f} option @cindex command line, option @option{-f} -The @option{-f} instructs the @command{awk} utility to get the @command{awk} program -from the file @var{source-file}. Any @value{FN} can be used for -@var{source-file}. For example, you could put the program: +The @option{-f} instructs the @command{awk} utility to get the +@command{awk} program from the file @var{source-file} (@pxref{Options}). +Any @value{FN} can be used for @var{source-file}. For example, you +could put the program: @example BEGIN @{ print "Don't Panic!" @} @@ -2460,16 +2479,7 @@ BEGIN @{ print "Don't Panic!" @} @noindent After making this file executable (with the @command{chmod} utility), simply type @samp{advice} -at the shell and the system arranges to run @command{awk}@footnote{The -line beginning with @samp{#!} lists the full @value{FN} of an interpreter -to run and an optional initial command-line argument to pass to that -interpreter. The operating system then runs the interpreter with the given -argument and the full argument list of the executed program. The first argument -in the list is the full @value{FN} of the @command{awk} program. -The rest of the -argument list contains either options to @command{awk}, or @value{DF}s, -or both. Note that on many systems @command{awk} may be found in -@file{/usr/bin} instead of in @file{/bin}. Caveat Emptor.} as if you had +at the shell and the system arranges to run @command{awk} as if you had typed @samp{awk -f advice}: @example @@ -2487,14 +2497,32 @@ Self-contained @command{awk} scripts are useful when you want to write a program that users can invoke without their having to know that the program is written in @command{awk}. -@cindex sidebar, Portability Issues with @samp{#!} +@cindex sidebar, Understanding @samp{#!} @ifdocbook @docbook -<sidebar><title>Portability Issues with @samp{#!}</title> +<sidebar><title>Understanding @samp{#!}</title> @end docbook @cindex portability, @code{#!} (executable scripts) +@command{awk} is an @dfn{interpreted} language. This means that the +@command{awk} utility reads your program and then processes your data +according to the instructions in your program. (This is different +from a @dfn{compiled} language such as C, where your program is first +compiled into machine code that is executed directly by your system's +hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +Many modern languages are interperted. + +The line beginning with @samp{#!} lists the full @value{FN} of an +interpreter to run and a single optional initial command-line argument +to pass to that interpreter. The operating system then runs the +interpreter with the given argument and the full argument list of the +executed program. The first argument in the list is the full @value{FN} +of the @command{awk} program. The rest of the argument list contains +either options to @command{awk}, or @value{DF}s, or both. Note that on +many systems @command{awk} may be found in @file{/usr/bin} instead of +in @file{/bin}. Caveat Emptor. + Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2506,8 +2534,7 @@ of some sort from @command{awk}. @cindex @code{ARGC}/@code{ARGV} variables, portability and @cindex portability, @code{ARGV} variable -Finally, -the value of @code{ARGV[0]} +Finally, the value of @code{ARGV[0]} (@pxref{Built-in Variables}) varies depending upon your operating system. Some systems put @samp{awk} there, some put the full pathname @@ -2523,11 +2550,29 @@ to provide your script name. @ifnotdocbook @cartouche -@center @b{Portability Issues with @samp{#!}} +@center @b{Understanding @samp{#!}} @cindex portability, @code{#!} (executable scripts) +@command{awk} is an @dfn{interpreted} language. This means that the +@command{awk} utility reads your program and then processes your data +according to the instructions in your program. (This is different +from a @dfn{compiled} language such as C, where your program is first +compiled into machine code that is executed directly by your system's +hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +Many modern languages are interperted. + +The line beginning with @samp{#!} lists the full @value{FN} of an +interpreter to run and a single optional initial command-line argument +to pass to that interpreter. The operating system then runs the +interpreter with the given argument and the full argument list of the +executed program. The first argument in the list is the full @value{FN} +of the @command{awk} program. The rest of the argument list contains +either options to @command{awk}, or @value{DF}s, or both. Note that on +many systems @command{awk} may be found in @file{/usr/bin} instead of +in @file{/bin}. Caveat Emptor. + Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2539,8 +2584,7 @@ of some sort from @command{awk}. @cindex @code{ARGC}/@code{ARGV} variables, portability and @cindex portability, @code{ARGV} variable -Finally, -the value of @code{ARGV[0]} +Finally, the value of @code{ARGV[0]} (@pxref{Built-in Variables}) varies depending upon your operating system. Some systems put @samp{awk} there, some put the full pathname @@ -2720,7 +2764,7 @@ Note that the single quote is not special within double quotes. @item Null strings are removed when they occur as part of a non-null -command-line argument, while explicit non-null objects are kept. +command-line argument, while explicit null objects are kept. For example, to specify that the field separator @code{FS} should be set to the null string, use: @@ -2867,7 +2911,9 @@ each line is considered to be one @dfn{record}. In the @value{DF} @file{mail-list}, each record contains the name of a person, his/her phone number, his/her email-address, and a code for their relationship -with the author of the list. An @samp{A} in the last column +with the author of the list. +The columns are aligned using spaces. +An @samp{A} in the last column means that the person is an acquaintance. An @samp{F} in the last column means that the person is a friend. An @samp{R} means that the person is a relative: @@ -2901,6 +2947,7 @@ of green crates shipped, the number of red boxes shipped, the number of orange bags shipped, and the number of blue packages shipped, respectively. There are 16 entries, covering the 12 months of last year and the first four months of the current year. +An empty line separates the data for the two years. @example @c file eg/data/inventory-shipped @@ -2996,34 +3043,39 @@ you can come up with different ways to do the same things shown here: @itemize @value{BULLET} @item -Print the length of the longest input line: +Print every line that is longer than 80 characters: @example -awk '@{ if (length($0) > max) max = length($0) @} - END @{ print max @}' data +awk 'length($0) > 80' data @end example +The sole rule has a relational expression as its pattern and it has no +action---so it uses the default action, printing the record. + @item -Print every line that is longer than 80 characters: +Print the length of the longest input line: @example -awk 'length($0) > 80' data +awk '@{ if (length($0) > max) max = length($0) @} + END @{ print max @}' data @end example -The sole rule has a relational expression as its pattern and it has no -action---so it uses the default action, printing the record. +The code associated with @code{END} executes after all +input has been read; it's the other side of the coin to @code{BEGIN}. @cindex @command{expand} utility @item Print the length of the longest line in @file{data}: @example -expand data | awk '@{ if (x < length()) x = length() @} +expand data | awk '@{ if (x < length($0)) x = length($0) @} END @{ print "maximum line length is " x @}' @end example +This example differs slightly from the previous one: The input is processed by the @command{expand} utility to change TABs -into spaces, so the widths compared are actually the right-margin columns. +into spaces, so the widths compared are actually the right-margin columns, +as opposed to the number of input characters on each line. @item Print every line that has at least one field: @@ -3150,8 +3202,8 @@ features that haven't been covered yet, so don't worry if you don't understand all the details: @example -LC_ALL=C ls -l | awk '$6 == "Nov" @{ sum += $5 @} - END @{ print sum @}' +ls -l | awk '$6 == "Nov" @{ sum += $5 @} + END @{ print sum @}' @end example @cindex @command{ls} utility @@ -3369,7 +3421,7 @@ and array sorting. As we develop our presentation of the @command{awk} language, we introduce most of the variables and many of the functions. They are described -systematically in @ref{Built-in Variables}, and +systematically in @ref{Built-in Variables}, and in @ref{Built-in}. @node When @@ -3404,33 +3456,30 @@ eight-bit microprocessors, and a microcode assembler for a special-purpose Prolog computer. While the original @command{awk}'s capabilities were strained by tasks -of such complexity, modern versions are more capable. Even Brian Kernighan's -version of @command{awk} has fewer predefined limits, and those -that it has are much larger than they used to be. +of such complexity, modern versions are more capable. @cindex @command{awk} programs, complex -If you find yourself writing @command{awk} scripts of more than, say, a few -hundred lines, you might consider using a different programming -language. -The shell is good at string and -pattern matching; in addition, it allows powerful use of the system -utilities. More conventional languages, such as C, C++, and Java, offer -better facilities for system programming and for managing the complexity -of large programs. -Python offers a nice balance between high-level ease of programming and -access to system facilities. -Programs in these languages may require more lines -of source code than the equivalent @command{awk} programs, but they are -easier to maintain and usually run more efficiently. +If you find yourself writing @command{awk} scripts of more than, say, +a few hundred lines, you might consider using a different programming +language. The shell is good at string and pattern matching; in addition, +it allows powerful use of the system utilities. Python offers a nice +balance between high-level ease of programming and access to system +facilities.@footnote{Other popular scripting languages include Ruby +and Perl.} @node Intro Summary @section Summary +@c FIXME: Review this chapter for summary of builtin functions called. @itemize @value{BULLET} @item Programs in @command{awk} consist of @var{pattern}-@var{action} pairs. @item +An @var{action} without a @var{pattern} always runs. The default +@var{action} for a pattern without one is @samp{@{ print $0 @}}. + +@item Use either @samp{awk '@var{program}' @var{files}} or @@ -3652,7 +3701,7 @@ multibyte characters. This option is an easy way to tell @command{gawk}: @cindex compatibility mode (@command{gawk}), specifying Specify @dfn{compatibility mode}, in which the GNU extensions to the @command{awk} language are disabled, so that @command{gawk} behaves just -like Brian Kernighan's version @command{awk}. +like BWK @command{awk}. @xref{POSIX/GNU}, which summarizes the extensions. @ifclear FOR_PRINT @@ -3737,7 +3786,7 @@ Command-line variable assignments of the form This option is particularly necessary for World Wide Web CGI applications that pass arguments through the URL; using this option prevents a malicious (or other) user from passing in options, assignments, or @command{awk} source -code (via @option{--source}) to the CGI application. This option should be used +code (via @option{-e}) to the CGI application. This option should be used with @samp{#!} scripts (@pxref{Executable Scripts}), like so: @example @@ -3783,7 +3832,7 @@ Second, because this option is intended to be used with code libraries, @command{gawk} does not recognize such files as constituting main program 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. +or on the command line. @item @option{-l} @var{ext} @itemx @option{--load} @var{ext} @@ -3807,7 +3856,7 @@ a shared library. This feature is described in detail in @ref{Dynamic Extension @cindex warnings, issuing Warn about constructs that are dubious or nonportable to other @command{awk} implementations. -No space is allowed between the @option{-D} and @var{value}, if +No space is allowed between the @option{-L} and @var{value}, if @var{value} is supplied. Some warnings are issued when @command{gawk} first reads your program. Others are issued at runtime, as your program executes. @@ -3926,7 +3975,7 @@ Newlines are not allowed after @samp{?} or @samp{:} @cindex @code{FS} variable, as TAB character @item -Specifying @samp{-Ft} on the command-line does not set the value +Specifying @samp{-Ft} on the command line does not set the value of @code{FS} to be a single TAB character (@pxref{Field Separators}). @@ -4023,14 +4072,14 @@ source of data.) Because it is clumsy using the standard @command{awk} mechanisms to mix source file and command-line @command{awk} programs, @command{gawk} -provides the @option{--source} option. This does not require you to +provides the @option{-e} option. This does not require you to pre-empt the standard input for your source code; it allows you to easily mix command-line and library source code (@pxref{AWKPATH Variable}). -As with @option{-f}, the @option{--source} and @option{--include} +As with @option{-f}, the @option{-e} and @option{-i} options may also be used multiple times on the command line. -@cindex @option{--source} option -If no @option{-f} or @option{--source} option is specified, then @command{gawk} +@cindex @option{-e} option +If no @option{-f} or @option{-e} option is specified, then @command{gawk} uses the first non-option command-line argument as the text of the program source code. @@ -4098,6 +4147,11 @@ included. As each element of @code{ARGV} is processed, @command{gawk} sets the variable @code{ARGIND} to the index in @code{ARGV} of the current element. +@c FIXME: One day, move the ARGC and ARGV node closer to here. +Changing @code{ARGC} and @code{ARGV} in your @command{awk} program lets +you control how @command{awk} processes the input files; this is described +in more detail in @ref{ARGC and ARGV}. + @cindex input files, variable assignments and @cindex variable assignments and input files The distinction between @value{FN} arguments and variable-assignment @@ -4172,7 +4226,7 @@ with @code{getline}. Some other versions of @command{awk} also support this, but it is not standard. (Some operating systems provide a @file{/dev/stdin} file -in the file system; however, @command{gawk} always processes +in the filesystem; however, @command{gawk} always processes this @value{FN} itself.) @node Environment Variables @@ -4198,7 +4252,7 @@ behaves. @cindex differences in @command{awk} and @command{gawk}, @code{AWKPATH} environment variable @ifinfo The previous @value{SECTION} described how @command{awk} program files can be named -on the command-line with the @option{-f} option. +on the command line with the @option{-f} option. @end ifinfo In most @command{awk} implementations, you must supply a precise path name for each program @@ -4226,7 +4280,7 @@ standard directory in the default path and then specified on the command line with a short @value{FN}. Otherwise, the full @value{FN} would have to be typed for each file. -By using the @option{-i} option, or the @option{--source} and @option{-f} options, your command-line +By using the @option{-i} option, or the @option{-e} and @option{-f} options, your command-line @command{awk} programs can use facilities in @command{awk} library files (@pxref{Library Functions}). Path searching is not done if @command{gawk} is in compatibility mode. @@ -4293,7 +4347,7 @@ list are meant to be used by regular users. @table @env @item POSIXLY_CORRECT -Causes @command{gawk} to switch POSIX compatibility +Causes @command{gawk} to switch to POSIX compatibility mode, disabling all traditional and GNU extensions. @xref{Options}. @@ -4326,7 +4380,7 @@ file as the size of the memory buffer to allocate for I/O. Otherwise, the value should be a number, and @command{gawk} uses that number as the size of the buffer to allocate. (When this variable is not set, @command{gawk} uses the smaller of the file's size and the ``default'' -blocksize, which is usually the file systems I/O blocksize.) +blocksize, which is usually the filesystems I/O blocksize.) @item AWK_HASH If this variable exists with a value of @samp{gst}, @command{gawk} @@ -4399,6 +4453,9 @@ to @code{EXIT_FAILURE}. This @value{SECTION} describes a feature that is specific to @command{gawk}. +@cindex @code{@@include} directive +@cindex file inclusion, @code{@@include} directive +@cindex including files, @code{@@include} directive The @code{@@include} keyword can be used to read external @command{awk} source files. This gives you the ability to split large @command{awk} source files into smaller, more manageable pieces, and also lets you reuse common @command{awk} @@ -4518,6 +4575,9 @@ and this also applies to files named with @code{@@include}. This @value{SECTION} describes a feature that is specific to @command{gawk}. +@cindex @code{@@load} directive +@cindex loading extensions, @code{@@load} directive +@cindex extensions, loading, @code{@@load} directive The @code{@@load} keyword can be used to read external @command{awk} extensions (stored as system shared libraries). This allows you to link in compiled code that may offer superior @@ -4659,9 +4719,9 @@ or to run @command{awk}. @item -The three standard @command{awk} options are @option{-f}, @option{-F} -and @option{-v}. @command{gawk} supplies these and many others, as well -as corresponding GNU-style long options. +The three standard options for all versions of @command{awk} are +@option{-f}, @option{-F} and @option{-v}. @command{gawk} supplies these +and many others, as well as corresponding GNU-style long options. @item Non-option command-line arguments are usually treated as @value{FN}s, @@ -4719,7 +4779,7 @@ The simplest regular expression is a sequence of letters, numbers, or both. Such a regexp matches any string that contains that sequence. Thus, the regexp @samp{foo} matches any string containing @samp{foo}. Therefore, the pattern @code{/foo/} matches any input record containing -the three characters @samp{foo} @emph{anywhere} in the record. Other +the three adjacent characters @samp{foo} @emph{anywhere} in the record. Other kinds of regexps let you specify more complicated classes of strings. @ifnotinfo @@ -4733,10 +4793,10 @@ regular expressions work, we present more complicated instances. * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between @samp{[...]}. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. @end menu @@ -4928,20 +4988,30 @@ between @samp{0} and @samp{7}. For example, the code for the ASCII ESC @item \x@var{hh}@dots{} The hexadecimal value @var{hh}, where @var{hh} stands for a sequence of hexadecimal digits (@samp{0}--@samp{9}, and either @samp{A}--@samp{F} -or @samp{a}--@samp{f}). Like the same construct -in ISO C, the escape sequence continues until the first nonhexadecimal -digit is seen. @value{COMMONEXT} +or @samp{a}--@samp{f}). A maximum of two digts are allowed after +the @samp{\x}. Any further hexadecimal digits are treated as simple +letters or numbers. @value{COMMONEXT} + +@quotation CAUTION +In ISO C, the escape sequence continues until the first nonhexadecimal +digit is seen. +@c FIXME: Add exact version here. +For many years, @command{gawk} would continue incorporating +hexadecimal digits into the value until a non-hexadecimal digit +or the end of the string was encountered. However, using more than two hexadecimal digits produces -undefined results. (The @samp{\x} escape sequence is not allowed in -POSIX @command{awk}.) +@end quotation @cindex @code{\} (backslash), @code{\/} escape sequence @cindex backslash (@code{\}), @code{\/} escape sequence @item \/ A literal slash (necessary for regexp constants only). This sequence is used when you want to write a regexp -constant that contains a slash. Because the regexp is delimited by -slashes, you need to escape the slash that is part of the pattern, +constant that contains a slash +(such as @code{/.*:\/home\/[[:alnum:]]+:.*/}; the @samp{[[:alnum:]]} +notation is discussed shortly, in @ref{Bracket Expressions}). +Because the regexp is delimited by +slashes, you need to escape any slash that is part of the pattern, in order to tell @command{awk} to keep processing the rest of the regexp. @cindex @code{\} (backslash), @code{\"} escape sequence @@ -4949,8 +5019,10 @@ in order to tell @command{awk} to keep processing the rest of the regexp. @item \" A literal double quote (necessary for string constants only). This sequence is used when you want to write a string -constant that contains a double quote. Because the string is delimited by -double quotes, you need to escape the quote that is part of the string, +constant that contains a double quote +(such as @code{"He said \"hi!\" to her."}). +Because the string is delimited by +double quotes, you need to escape any quote that is part of the string, in order to tell @command{awk} to keep processing the rest of the string. @end table @@ -5011,7 +5083,7 @@ leaves what happens as undefined. There are two choices: @cindex Brian Kernighan's @command{awk} @table @asis @item Strip the backslash out -This is what Brian Kernighan's @command{awk} and @command{gawk} both do. +This is what BWK @command{awk} and @command{gawk} both do. For example, @code{"a\qc"} is the same as @code{"aqc"}. (Because this is such an easy bug both to introduce and to miss, @command{gawk} warns you about it.) @@ -5054,7 +5126,7 @@ leaves what happens as undefined. There are two choices: @cindex Brian Kernighan's @command{awk} @table @asis @item Strip the backslash out -This is what Brian Kernighan's @command{awk} and @command{gawk} both do. +This is what BWK @command{awk} and @command{gawk} both do. For example, @code{"a\qc"} is the same as @code{"aqc"}. (Because this is such an easy bug both to introduce and to miss, @command{gawk} warns you about it.) @@ -5142,7 +5214,7 @@ The escape sequences described @ifnotinfo earlier @end ifnotinfo -in @ref{Escape Sequences}, +in @DBREF{Escape Sequences} are valid inside a regexp. They are introduced by a @samp{\} and are recognized and converted into corresponding real characters as the very first step in processing regexps. @@ -5239,12 +5311,11 @@ or @samp{k}. @cindex vertical bar (@code{|}) @item @code{|} This is the @dfn{alternation operator} and it is used to specify -alternatives. -The @samp{|} has the lowest precedence of all the regular -expression operators. -For example, @samp{^P|[[:digit:]]} -matches any string that matches either @samp{^P} or @samp{[[:digit:]]}. This -means it matches any string that starts with @samp{P} or contains a digit. +alternatives. The @samp{|} has the lowest precedence of all the regular +expression operators. For example, @samp{^P|[aeiouy]} matches any string +that matches either @samp{^P} or @samp{[aeiouy]}. This means it matches +any string that starts with @samp{P} or contains (anywhere within it) +a lowercase English vowel. The alternation applies to the largest possible regexps on either side. @@ -5268,14 +5339,15 @@ applies the @samp{*} symbol to the preceding @samp{h} and looks for matches of one @samp{p} followed by any number of @samp{h}s. This also matches just @samp{p} if no @samp{h}s are present. -The @samp{*} repeats the @emph{smallest} possible preceding expression. -(Use parentheses if you want to repeat a larger expression.) It finds -as many repetitions as possible. For example, -@samp{awk '/\(c[ad][ad]*r x\)/ @{ print @}' sample} -prints every record in @file{sample} containing a string of the form -@samp{(car x)}, @samp{(cdr x)}, @samp{(cadr x)}, and so on. -Notice the escaping of the parentheses by preceding them -with backslashes. +There are two subtle points to understand about how @samp{*} works. +First, the @samp{*} applies only to the single preceding regular expression +component (e.g., in @samp{ph*}, it applies just to the @samp{h}). +To cause @samp{*} to apply to a larger sub-expression, use parentheses: +@samp{(ph)*} matches @samp{ph}, @samp{phph}, @samp{phphph} and so on. + +Second, @samp{*} finds as many repetititons as possible. If the text +to be matched is @samp{phhhhhhhhhhhhhhooey}, @samp{ph*} matches all of +the @samp{h}s. @cindex @code{+} (plus sign), regexp operator @cindex plus sign (@code{+}), regexp operator @@ -5284,12 +5356,6 @@ This symbol is similar to @samp{*}, except that the preceding expression must be matched at least once. This means that @samp{wh+y} would match @samp{why} and @samp{whhy}, but not @samp{wy}, whereas @samp{wh*y} would match all three. -The following is a simpler -way of writing the last @samp{*} example: - -@example -awk '/\(c[ad]+r x\)/ @{ print @}' sample -@end example @cindex @code{?} (question mark), regexp operator @cindex question mark (@code{?}), regexp operator @@ -5384,7 +5450,7 @@ Within a bracket expression, a @dfn{range expression} consists of two characters separated by a hyphen. It matches any single character that sorts between the two characters, based upon the system's native character set. For example, @samp{[0-9]} is equivalent to @samp{[0123456789]}. -(See @ref{Ranges and Locales}, for an explanation of how the POSIX +(See @DBREF{Ranges and Locales} for an explanation of how the POSIX standard and @command{gawk} have changed over time. This is mainly of historical interest.) @@ -5403,6 +5469,9 @@ bracket expression, put a @samp{\} in front of it. For example: @noindent matches either @samp{d} or @samp{]}. +Additionally, if you place @samp{]} right after the opening +@samp{[}, the closing bracket is treated as one of the +characters to be matched. @cindex POSIX @command{awk}, bracket expressions and @cindex Extended Regular Expressions (EREs) @@ -5514,6 +5583,204 @@ they do not recognize collating symbols or equivalence classes. @c maybe one day ... @c ENDOFRANGE charlist +@node Leftmost Longest +@section How Much Text Matches? + +@cindex regular expressions, leftmost longest match +@c @cindex matching, leftmost longest +Consider the following: + +@example +echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' +@end example + +This example uses the @code{sub()} function (which we haven't discussed yet; +@pxref{String Functions}) +to make a change to the input record. Here, the regexp @code{/a+/} +indicates ``one or more @samp{a} characters,'' and the replacement +text is @samp{<A>}. + +The input contains four @samp{a} characters. +@command{awk} (and POSIX) regular expressions always match +the leftmost, @emph{longest} sequence of input characters that can +match. Thus, all four @samp{a} characters are +replaced with @samp{<A>} in this example: + +@example +$ @kbd{echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'} +@print{} <A>bcd +@end example + +For simple match/no-match tests, this is not so important. But when doing +text matching and substitutions with the @code{match()}, @code{sub()}, @code{gsub()}, +and @code{gensub()} functions, it is very important. +@ifinfo +@xref{String Functions}, +for more information on these functions. +@end ifinfo +Understanding this principle is also important for regexp-based record +and field splitting (@pxref{Records}, +and also @pxref{Field Separators}). + +@node Computed Regexps +@section Using Dynamic Regexps + +@c STARTOFRANGE dregexp +@cindex regular expressions, computed +@c STARTOFRANGE regexpd +@cindex regular expressions, dynamic +@cindex @code{~} (tilde), @code{~} operator +@cindex tilde (@code{~}), @code{~} operator +@cindex @code{!} (exclamation point), @code{!~} operator +@cindex exclamation point (@code{!}), @code{!~} operator +@c @cindex operators, @code{~} +@c @cindex operators, @code{!~} +The righthand side of a @samp{~} or @samp{!~} operator need not be a +regexp constant (i.e., a string of characters between slashes). It may +be any expression. The expression is evaluated and converted to a string +if necessary; the contents of the string are then used as the +regexp. A regexp computed in this way is called a @dfn{dynamic +regexp} or a @dfn{computed regexp}: + +@example +BEGIN @{ digits_regexp = "[[:digit:]]+" @} +$0 ~ digits_regexp @{ print @} +@end example + +@noindent +This sets @code{digits_regexp} to a regexp that describes one or more digits, +and tests whether the input record matches this regexp. + +@quotation NOTE +When using the @samp{~} and @samp{!~} +operators, there is a difference between a regexp constant +enclosed in slashes and a string constant enclosed in double quotes. +If you are going to use a string constant, you have to understand that +the string is, in essence, scanned @emph{twice}: the first time when +@command{awk} reads your program, and the second time when it goes to +match the string on the lefthand side of the operator with the pattern +on the right. This is true of any string-valued expression (such as +@code{digits_regexp}, shown previously), not just string constants. +@end quotation + +@cindex regexp constants, slashes vs.@: quotes +@cindex @code{\} (backslash), in regexp constants +@cindex backslash (@code{\}), in regexp constants +@cindex @code{"} (double quote), in regexp constants +@cindex double quote (@code{"}), in regexp constants +What difference does it make if the string is +scanned twice? The answer has to do with escape sequences, and particularly +with backslashes. To get a backslash into a regular expression inside a +string, you have to type two backslashes. + +For example, @code{/\*/} is a regexp constant for a literal @samp{*}. +Only one backslash is needed. To do the same thing with a string, +you have to type @code{"\\*"}. The first backslash escapes the +second one so that the string actually contains the +two characters @samp{\} and @samp{*}. + +@cindex troubleshooting, regexp constants vs.@: string constants +@cindex regexp constants, vs.@: string constants +@cindex string constants, vs.@: regexp constants +Given that you can use both regexp and string constants to describe +regular expressions, which should you use? The answer is ``regexp +constants,'' for several reasons: + +@itemize @value{BULLET} +@item +String constants are more complicated to write and +more difficult to read. Using regexp constants makes your programs +less error-prone. Not understanding the difference between the two +kinds of constants is a common source of errors. + +@item +It is more efficient to use regexp constants. @command{awk} can note +that you have supplied a regexp and store it internally in a form that +makes pattern matching more efficient. When using a string constant, +@command{awk} must first convert the string into this internal form and +then perform the pattern matching. + +@item +Using regexp constants is better form; it shows clearly that you +intend a regexp match. +@end itemize + +@cindex sidebar, Using @code{\n} in Bracket Expressions of Dynamic Regexps +@ifdocbook +@docbook +<sidebar><title>Using @code{\n} in Bracket Expressions of Dynamic Regexps</title> +@end docbook + +@cindex regular expressions, dynamic, with embedded newlines +@cindex newlines, in dynamic regexps + +Some versions of @command{awk} do not allow the newline +character to be used inside a bracket expression for a dynamic regexp: + +@example +$ @kbd{awk '$0 ~ "[ \t\n]"'} +@error{} awk: newline in character class [ +@error{} ]... +@error{} source line number 1 +@error{} context is +@error{} >>> <<< +@end example + +@cindex newlines, in regexp constants +But a newline in a regexp constant works with no problem: + +@example +$ @kbd{awk '$0 ~ /[ \t\n]/'} +@kbd{here is a sample line} +@print{} here is a sample line +@kbd{Ctrl-d} +@end example + +@command{gawk} does not have this problem, and it isn't likely to +occur often in practice, but it's worth noting for future reference. + +@docbook +</sidebar> +@end docbook +@end ifdocbook + +@ifnotdocbook +@cartouche +@center @b{Using @code{\n} in Bracket Expressions of Dynamic Regexps} + + +@cindex regular expressions, dynamic, with embedded newlines +@cindex newlines, in dynamic regexps + +Some versions of @command{awk} do not allow the newline +character to be used inside a bracket expression for a dynamic regexp: + +@example +$ @kbd{awk '$0 ~ "[ \t\n]"'} +@error{} awk: newline in character class [ +@error{} ]... +@error{} source line number 1 +@error{} context is +@error{} >>> <<< +@end example + +@cindex newlines, in regexp constants +But a newline in a regexp constant works with no problem: + +@example +$ @kbd{awk '$0 ~ /[ \t\n]/'} +@kbd{here is a sample line} +@print{} here is a sample line +@kbd{Ctrl-d} +@end example + +@command{gawk} does not have this problem, and it isn't likely to +occur often in practice, but it's worth noting for future reference. +@end cartouche +@end ifnotdocbook +@c ENDOFRANGE dregexp +@c ENDOFRANGE regexpd + @node GNU Regexp Operators @section @command{gawk}-Specific Regexp Operators @@ -5677,7 +5944,7 @@ are allowed. Traditional Unix @command{awk} regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (@samp{[[:alnum:]]}, etc.) are supported, -as Brian Kernighan's @command{awk} does support them. +as BWK @command{awk} does support them. Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. @@ -5789,204 +6056,6 @@ Case is always significant in compatibility mode. @c ENDOFRANGE csregexp @c ENDOFRANGE regexpcs -@node Leftmost Longest -@section How Much Text Matches? - -@cindex regular expressions, leftmost longest match -@c @cindex matching, leftmost longest -Consider the following: - -@example -echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' -@end example - -This example uses the @code{sub()} function (which we haven't discussed yet; -@pxref{String Functions}) -to make a change to the input record. Here, the regexp @code{/a+/} -indicates ``one or more @samp{a} characters,'' and the replacement -text is @samp{<A>}. - -The input contains four @samp{a} characters. -@command{awk} (and POSIX) regular expressions always match -the leftmost, @emph{longest} sequence of input characters that can -match. Thus, all four @samp{a} characters are -replaced with @samp{<A>} in this example: - -@example -$ @kbd{echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'} -@print{} <A>bcd -@end example - -For simple match/no-match tests, this is not so important. But when doing -text matching and substitutions with the @code{match()}, @code{sub()}, @code{gsub()}, -and @code{gensub()} functions, it is very important. -@ifinfo -@xref{String Functions}, -for more information on these functions. -@end ifinfo -Understanding this principle is also important for regexp-based record -and field splitting (@pxref{Records}, -and also @pxref{Field Separators}). - -@node Computed Regexps -@section Using Dynamic Regexps - -@c STARTOFRANGE dregexp -@cindex regular expressions, computed -@c STARTOFRANGE regexpd -@cindex regular expressions, dynamic -@cindex @code{~} (tilde), @code{~} operator -@cindex tilde (@code{~}), @code{~} operator -@cindex @code{!} (exclamation point), @code{!~} operator -@cindex exclamation point (@code{!}), @code{!~} operator -@c @cindex operators, @code{~} -@c @cindex operators, @code{!~} -The righthand side of a @samp{~} or @samp{!~} operator need not be a -regexp constant (i.e., a string of characters between slashes). It may -be any expression. The expression is evaluated and converted to a string -if necessary; the contents of the string are then used as the -regexp. A regexp computed in this way is called a @dfn{dynamic -regexp} or a @dfn{computed regexp}: - -@example -BEGIN @{ digits_regexp = "[[:digit:]]+" @} -$0 ~ digits_regexp @{ print @} -@end example - -@noindent -This sets @code{digits_regexp} to a regexp that describes one or more digits, -and tests whether the input record matches this regexp. - -@quotation NOTE -When using the @samp{~} and @samp{!~} -operators, there is a difference between a regexp constant -enclosed in slashes and a string constant enclosed in double quotes. -If you are going to use a string constant, you have to understand that -the string is, in essence, scanned @emph{twice}: the first time when -@command{awk} reads your program, and the second time when it goes to -match the string on the lefthand side of the operator with the pattern -on the right. This is true of any string-valued expression (such as -@code{digits_regexp}, shown previously), not just string constants. -@end quotation - -@cindex regexp constants, slashes vs.@: quotes -@cindex @code{\} (backslash), in regexp constants -@cindex backslash (@code{\}), in regexp constants -@cindex @code{"} (double quote), in regexp constants -@cindex double quote (@code{"}), in regexp constants -What difference does it make if the string is -scanned twice? The answer has to do with escape sequences, and particularly -with backslashes. To get a backslash into a regular expression inside a -string, you have to type two backslashes. - -For example, @code{/\*/} is a regexp constant for a literal @samp{*}. -Only one backslash is needed. To do the same thing with a string, -you have to type @code{"\\*"}. The first backslash escapes the -second one so that the string actually contains the -two characters @samp{\} and @samp{*}. - -@cindex troubleshooting, regexp constants vs.@: string constants -@cindex regexp constants, vs.@: string constants -@cindex string constants, vs.@: regexp constants -Given that you can use both regexp and string constants to describe -regular expressions, which should you use? The answer is ``regexp -constants,'' for several reasons: - -@itemize @value{BULLET} -@item -String constants are more complicated to write and -more difficult to read. Using regexp constants makes your programs -less error-prone. Not understanding the difference between the two -kinds of constants is a common source of errors. - -@item -It is more efficient to use regexp constants. @command{awk} can note -that you have supplied a regexp and store it internally in a form that -makes pattern matching more efficient. When using a string constant, -@command{awk} must first convert the string into this internal form and -then perform the pattern matching. - -@item -Using regexp constants is better form; it shows clearly that you -intend a regexp match. -@end itemize - -@cindex sidebar, Using @code{\n} in Bracket Expressions of Dynamic Regexps -@ifdocbook -@docbook -<sidebar><title>Using @code{\n} in Bracket Expressions of Dynamic Regexps</title> -@end docbook - -@cindex regular expressions, dynamic, with embedded newlines -@cindex newlines, in dynamic regexps - -Some versions of @command{awk} do not allow the newline -character to be used inside a bracket expression for a dynamic regexp: - -@example -$ @kbd{awk '$0 ~ "[ \t\n]"'} -@error{} awk: newline in character class [ -@error{} ]... -@error{} source line number 1 -@error{} context is -@error{} >>> <<< -@end example - -@cindex newlines, in regexp constants -But a newline in a regexp constant works with no problem: - -@example -$ @kbd{awk '$0 ~ /[ \t\n]/'} -@kbd{here is a sample line} -@print{} here is a sample line -@kbd{Ctrl-d} -@end example - -@command{gawk} does not have this problem, and it isn't likely to -occur often in practice, but it's worth noting for future reference. - -@docbook -</sidebar> -@end docbook -@end ifdocbook - -@ifnotdocbook -@cartouche -@center @b{Using @code{\n} in Bracket Expressions of Dynamic Regexps} - - -@cindex regular expressions, dynamic, with embedded newlines -@cindex newlines, in dynamic regexps - -Some versions of @command{awk} do not allow the newline -character to be used inside a bracket expression for a dynamic regexp: - -@example -$ @kbd{awk '$0 ~ "[ \t\n]"'} -@error{} awk: newline in character class [ -@error{} ]... -@error{} source line number 1 -@error{} context is -@error{} >>> <<< -@end example - -@cindex newlines, in regexp constants -But a newline in a regexp constant works with no problem: - -@example -$ @kbd{awk '$0 ~ /[ \t\n]/'} -@kbd{here is a sample line} -@print{} here is a sample line -@kbd{Ctrl-d} -@end example - -@command{gawk} does not have this problem, and it isn't likely to -occur often in practice, but it's worth noting for future reference. -@end cartouche -@end ifnotdocbook -@c ENDOFRANGE dregexp -@c ENDOFRANGE regexpd - @node Regexp Summary @section Summary @@ -5997,7 +6066,7 @@ In @command{awk}, regular expression constants are written enclosed between slashes: @code{/}@dots{}@code{/}. @item -Regexp constants may be used by standalone in patterns and +Regexp constants may be used standalone in patterns and in conditional expressions, or as part of matching expressions using the @samp{~} and @samp{!~} operators. @@ -6027,7 +6096,7 @@ the match, such as for text substitution and when the record separator is a regexp. @item -Matching expressions may use dynamic regexps; that is string values +Matching expressions may use dynamic regexps, that is, string values treated as regular expressions. @end itemize @@ -6079,7 +6148,7 @@ used with it do not have to be named on the @command{awk} command line * Getline:: Reading files under explicit program control using the @code{getline} function. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on the +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -6094,16 +6163,13 @@ used with it do not have to be named on the @command{awk} command line @cindex records, splitting input into @cindex @code{NR} variable @cindex @code{FNR} variable -The @command{awk} utility divides the input for your @command{awk} -program into records and fields. -@command{awk} keeps track of the number of records that have -been read -so far -from the current input file. This value is stored in a -built-in variable called @code{FNR}. It is reset to zero when a new -file is started. Another built-in variable, @code{NR}, records the total -number of input records read so far from all @value{DF}s. It starts at zero, -but is never automatically reset to zero. +@command{awk} divides the input for your program into records and fields. +It keeps track of the number of records that have been read so far from +the current input file. This value is stored in a built-in variable +called @code{FNR} which is reset to zero when a new file is started. +Another built-in variable, @code{NR}, records the total number of input +records read so far from all @value{DF}s. It starts at zero, but is +never automatically reset to zero. @menu * awk split records:: How standard @command{awk} splits records. @@ -6310,17 +6376,17 @@ with optional leading and/or trailing whitespace: @example $ @kbd{echo record 1 AAAA record 2 BBBB record 3 |} > @kbd{gawk 'BEGIN @{ RS = "\n|( *[[:upper:]]+ *)" @}} -> @kbd{@{ print "Record =", $0, "and RT =", RT @}'} -@print{} Record = record 1 and RT = AAAA -@print{} Record = record 2 and RT = BBBB -@print{} Record = record 3 and RT = -@print{} +> @kbd{@{ print "Record =", $0,"and RT = [" RT "]" @}'} +@print{} Record = record 1 and RT = [ AAAA ] +@print{} Record = record 2 and RT = [ BBBB ] +@print{} Record = record 3 and RT = [ +@print{} ] @end example @noindent -The final line of output has an extra blank line. This is because the -value of @code{RT} is a newline, and the @code{print} statement -supplies its own terminating newline. +The square brackets delineate the contents of @code{RT}, letting you +see the leading and trailing whitespace. The final value of @code{RT} +@code{RT} is a newline. @xref{Simple Sed}, for a more useful example of @code{RS} as a regexp and @code{RT}. @@ -6834,7 +6900,7 @@ with a statement such as @samp{$1 = $1}, as described earlier. * Default Field Splitting:: How fields are normally separated. * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting @code{FS} from the command-line. +* Command Line Field Separator:: Setting @code{FS} from the command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @end menu @@ -7035,7 +7101,7 @@ should not rely on any specific behavior in your programs. @value{DARKCORNER} @cindex Brian Kernighan's @command{awk} -As a point of information, Brian Kernighan's @command{awk} allows @samp{^} +As a point of information, BWK @command{awk} allows @samp{^} to match only at the beginning of the record. @command{gawk} also works this way. For example: @@ -7090,7 +7156,7 @@ behaves this way. @node Command Line Field Separator @subsection Setting @code{FS} from the Command Line -@cindex @option{-F} option, command line +@cindex @option{-F} option, command-line @cindex field separator, on command line @cindex command line, @code{FS} on@comma{} setting @cindex @code{FS} variable, setting from command line @@ -7140,6 +7206,8 @@ shell, without any quotes, the @samp{\} gets deleted, so @command{awk} figures that you really want your fields to be separated with TABs and not @samp{t}s. Use @samp{-v FS="t"} or @samp{-F"[t]"} on the command line if you really do want to separate your fields with @samp{t}s. +Use @samp{-F '\t'} when not in compatibility mode to specify that TABs +separate fields. As an example, let's use an @command{awk} program file called @file{edu.awk} that contains the pattern @code{/edu/} and the action @samp{print $1}: @@ -7290,7 +7358,7 @@ root @noindent on an incorrect implementation of @command{awk}, while @command{gawk} -prints something like: +prints the full first line of the file, something like: @example root:nSijPlPhZZwgE:0:0:Root:/: @@ -7343,7 +7411,7 @@ root @noindent on an incorrect implementation of @command{awk}, while @command{gawk} -prints something like: +prints the full first line of the file, something like: @example root:nSijPlPhZZwgE:0:0:Root:/: @@ -7480,7 +7548,7 @@ haven't been introduced yet. BEGIN @{ FIELDWIDTHS = "9 6 10 6 7 7 35" @} NR > 2 @{ idle = $4 - sub(/^ */, "", idle) # strip leading spaces + sub(/^ +/, "", idle) # strip leading spaces if (idle == "") idle = 0 if (idle ~ /:/) @{ @@ -7638,6 +7706,8 @@ if (substr($i, 1, 1) == "\"") @{ As with @code{FS}, the @code{IGNORECASE} variable (@pxref{User-modified}) affects field splitting with @code{FPAT}. +Assigning a value to @code{FPAT} overrides field splitting +with @code{FS} and with @code{FIELDWIDTHS}. Similar to @code{FIELDWIDTHS}, the value of @code{PROCINFO["FS"]} will be @code{"FPAT"} if content-based field splitting is being used. @@ -7661,6 +7731,12 @@ FPAT = "([^,]*)|(\"[^\"]+\")" Finally, the @code{patsplit()} function makes the same functionality available for splitting regular strings (@pxref{String Functions}). +To recap, @command{gawk} provides three independent methods +to split input records into fields. @command{gawk} uses whichever +mechanism was last chosen based on which of the three +variables---@code{FS}, @code{FIELDWIDTHS}, and @code{FPAT}---was +last assigned to. + @node Multiple Line @section Multiple-Line Records @@ -7882,7 +7958,7 @@ and have a good knowledge of how @command{awk} works. @cindex @code{getline} command, return values @cindex @option{--sandbox} option, input redirection with @code{getline} -The @code{getline} command returns one if it finds a record and zero if +The @code{getline} command returns 1 if it finds a record and 0 if it encounters the end of the file. If there is some error in getting a record, such as a file that cannot be opened, then @code{getline} returns @minus{}1. In this case, @command{gawk} sets the variable @@ -7922,32 +7998,58 @@ finished processing the current record, but want to do some special processing on the next record @emph{right now}. For example: @example +# Remove text between /* and */, inclusive @{ - if ((t = index($0, "/*")) != 0) @{ - # value of `tmp' will be "" if t is 1 - tmp = substr($0, 1, t - 1) - u = index(substr($0, t + 2), "*/") - offset = t + 2 - while (u == 0) @{ - if (getline <= 0) @{ + if ((i = index($0, "/*")) != 0) @{ + out = substr($0, 1, i - 1) # leading part of the string + rest = substr($0, i + 2) # ... */ ... + j = index(rest, "*/") # is */ in trailing part? + if (j > 0) @{ + rest = substr(rest, j + 2) # remove comment + @} else @{ + while (j == 0) @{ + # get more text + if (getline <= 0) @{ m = "unexpected EOF or error" m = (m ": " ERRNO) print m > "/dev/stderr" exit - @} - u = index($0, "*/") - offset = 0 - @} - # substr() expression will be "" if */ - # occurred at end of line - $0 = tmp substr($0, offset + u + 2) - @} - print $0 + @} + # build up the line using string concatenation + rest = rest $0 + j = index(rest, "*/") # is */ in trailing part? + if (j != 0) @{ + rest = substr(rest, j + 2) + break + @} + @} + @} + # build up the output line using string concatenation + $0 = out rest + @} + print $0 @} @end example +@c 8/2014: Here is some sample input: +@ignore +mon/*comment*/key +rab/*commen +t*/bit +horse /*comment*/more text +part 1 /*comment*/part 2 /*comment*/part 3 +no comment +@end ignore + This @command{awk} program deletes C-style comments (@samp{/* @dots{} -*/}) from the input. By replacing the @samp{print $0} with other +*/}) from the input. +It uses a number of features we haven't covered yet, including +string concatenation +(@pxref{Concatenation}) +and the @code{index()} and @code{substr()} built-in +functions +(@pxref{String Functions}). +By replacing the @samp{print $0} with other statements, you could perform more complicated processing on the decommented input, such as searching for matches of a regular expression. (This program has a subtle problem---it does not work if one @@ -8204,7 +8306,7 @@ Unfortunately, @command{gawk} has not been consistent in its treatment of a construct like @samp{@w{"echo "} "date" | getline}. Most versions, including the current version, treat it at as @samp{@w{("echo "} "date") | getline}. -(This how Brian Kernighan's @command{awk} behaves.) +(This how BWK @command{awk} behaves.) Some versions changed and treated it as @samp{@w{"echo "} ("date" | getline)}. (This is how @command{mawk} behaves.) @@ -8354,7 +8456,7 @@ probably by accident, and you should reconsider what it is you're trying to accomplish. @item -@ref{Getline Summary}, presents a table summarizing the +@DBREF{Getline Summary} presents a table summarizing the @code{getline} variants and which variables they can affect. It is worth noting that those variants which do not use redirection can cause @code{FILENAME} to be updated if they cause @@ -8525,10 +8627,10 @@ a connection before it can start reading any data, or the attempt to open a FIFO special file for reading can block indefinitely until some other process opens it for writing. -@node Command line directories +@node Command-line directories @section Directories On The Command Line -@cindex differences in @command{awk} and @command{gawk}, command line directories -@cindex directories, command line +@cindex differences in @command{awk} and @command{gawk}, command-line directories +@cindex directories, command-line @cindex command line, directories on According to the POSIX standard, files named on the @command{awk} @@ -8621,6 +8723,7 @@ Directories on the command line are fatal for standard @command{awk}; @end itemize +@c EXCLUDE START @node Input Exercises @section Exercises @@ -8637,9 +8740,10 @@ including abstentions, for each item. comments (@samp{/* @dots{} */}) from the input. That program does not work if one comment ends on one line and another one starts later on the same line. -Write a program that does handle multiple comments on the line. +That can be fixed by making one simple change. What is it? @end enumerate +@c EXCLUDE END @node Printing @chapter Printing Output @@ -8681,7 +8785,7 @@ and discusses the @code{close()} built-in function. descriptors. * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. @end menu @node Print @@ -8718,6 +8822,10 @@ double-quote characters, your text is taken as an @command{awk} expression, and you will probably get an error. Keep in mind that a space is printed between any two items. +Note that the @code{print} statement is a statement and not an +expression---you can't use it the pattern part of a pattern-action +statement, for example. + @node Print Examples @section @code{print} Statement Examples @@ -9691,7 +9799,7 @@ It then sends the list to the shell for execution. @c ENDOFRANGE reout @node Special Files -@section Special @value{FFN} in @command{gawk} +@section Special @value{FFN}s in @command{gawk} @c STARTOFRANGE gfn @cindex @command{gawk}, file names in @@ -9738,7 +9846,8 @@ print "Serious error detected!" | "cat 1>&2" @noindent This works by opening a pipeline to a shell command that can access the standard error stream that it inherits from the @command{awk} process. -This is far from elegant, and it is also inefficient, because it requires a +@c 8/2014: Mike Brennan says not to cite this as inefficient. So, fixed. +This is far from elegant, and it also requires a separate process. So people writing @command{awk} programs often don't do this. Instead, they send the error messages to the screen, like this: @@ -10187,7 +10296,8 @@ communications. @end itemize -@node Output exercises +@c EXCLUDE START +@node Output Exercises @section Exercises @enumerate @@ -10216,6 +10326,7 @@ BEGIN @{ print "Serious error detected!" > /dev/stderr @} @end example @end enumerate +@c EXCLUDE END @c ENDOFRANGE prnt @@ -10459,7 +10570,8 @@ A regexp constant is a regular expression description enclosed in slashes, such as @code{@w{/^beginning and end$/}}. Most regexps used in @command{awk} programs are constant, but the @samp{~} and @samp{!~} matching operators can also match computed or dynamic regexps -(which are just ordinary strings or variables that contain a regexp). +(which are typically just ordinary strings or variables that contain a regexp, +but could be a more complex expression). @c ENDOFRANGE cnst @node Using Constant Regexps @@ -10565,7 +10677,7 @@ function mysub(pat, repl, str, global) @c @cindex automatic warnings @c @cindex warnings, automatic In this example, the programmer wants to pass a regexp constant to the -user-defined function @code{mysub}, which in turn passes it on to +user-defined function @code{mysub()}, which in turn passes it on to either @code{sub()} or @code{gsub()}. However, what really happens is that the @code{pat} parameter is either one or zero, depending upon whether or not @code{$0} matches @code{/hi/}. @@ -10586,7 +10698,7 @@ on the @command{awk} command line. @menu * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line and a +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. @end menu @@ -11073,7 +11185,7 @@ print "something meaningful" > file name @cindex @command{mawk} utility @noindent This produces a syntax error with some versions of Unix -@command{awk}.@footnote{It happens that Brian Kernighan's +@command{awk}.@footnote{It happens that BWK @command{awk}, @command{gawk} and @command{mawk} all ``get it right,'' but you should not rely on this.} It is necessary to use the following: @@ -11158,7 +11270,7 @@ Otherwise, it's parsed as follows: @end display As mentioned earlier, -when doing concatenation, @emph{parenthesize}. Otherwise, +when mixing concatenation with other operators, @emph{parenthesize}. Otherwise, you're never quite sure what you'll get. @node Assignment Ops @@ -11416,7 +11528,7 @@ A workaround is: awk '/[=]=/' /dev/null @end example -@command{gawk} does not have this problem; Brian Kernighan's @command{awk} +@command{gawk} does not have this problem; BWK @command{awk} and @command{mawk} also do not (@pxref{Other Versions}). @docbook @@ -11462,7 +11574,7 @@ A workaround is: awk '/[=]=/' /dev/null @end example -@command{gawk} does not have this problem; Brian Kernighan's @command{awk} +@command{gawk} does not have this problem; BWK @command{awk} and @command{mawk} also do not (@pxref{Other Versions}). @end cartouche @end ifnotdocbook @@ -11754,19 +11866,14 @@ compares variables. @cindex numeric, strings @cindex strings, numeric @cindex POSIX @command{awk}, numeric strings and -The 1992 POSIX standard introduced +The POSIX standard introduced the concept of a @dfn{numeric string}, which is simply a string that looks like a number---for example, @code{@w{" +2"}}. This concept is used for determining the type of a variable. The type of the variable is important because the types of two variables determine how they are compared. +Variable typing follows these rules: -The various versions of the POSIX standard did not get the rules -quite right for several editions. Fortunately, as of at least the -2008 standard (and possibly earlier), the standard has been fixed, -and variable typing follows these rules:@footnote{@command{gawk} has -followed these rules for many years, -and it is gratifying that the POSIX standard is also now correct.} @itemize @value{BULLET} @item @@ -11919,7 +12026,7 @@ made of characters and is therefore also a string. Thus, for example, the string constant @w{@code{" +3.14"}}, when it appears in program source code, is a string---even though it looks numeric---and -is @emph{never} treated as number for comparison +is @emph{never} treated as a number for comparison purposes. In short, when one operand is a ``pure'' string, such as a string @@ -12236,7 +12343,7 @@ is ``short-circuited'' if the result can be determined part way through its evaluation. @cindex line continuations -Statements that use @samp{&&} or @samp{||} can be continued simply +Statements that end with @samp{&&} or @samp{||} can be continued simply by putting a newline after them. But you cannot put a newline in front of either of these operators without using backslash continuation (@pxref{Statements/Lines}). @@ -12255,7 +12362,7 @@ program is one way to print lines in between special bracketing lines: @example $1 == "START" @{ interested = ! interested; next @} -interested == 1 @{ print @} +interested @{ print @} $1 == "END" @{ interested = ! interested; next @} @end example @@ -12275,6 +12382,16 @@ bogus input data, but the point is to illustrate the use of `!', so we'll leave well enough alone. @end ignore +Most commonly, the @samp{!} operator is used in the conditions of +@code{if} and @code{while} statements, where it often makes more +sense to phrase the logic in the negative: + +@example +if (! @var{some condition} || @var{some other condition}) @{ + @var{@dots{} do whatever processing @dots{}} +@} +@end example + @cindex @code{next} statement @quotation NOTE The @code{next} statement is discussed in @@ -12895,7 +13012,7 @@ Contrast this with the following regular expression match, which accepts any record with a first field that contains @samp{li}: @example -$ @kbd{awk '$1 ~ /foo/ @{ print $2 @}' mail-list} +$ @kbd{awk '$1 ~ /li/ @{ print $2 @}' mail-list} @print{} 555-5553 @print{} 555-6699 @end example @@ -13167,7 +13284,7 @@ rule. It contains the number of fields from the last input record. Most probably due to an oversight, the standard does not say that @code{$0} is also preserved, although logically one would think that it should be. In fact, @command{gawk} does preserve the value of @code{$0} for use in -@code{END} rules. Be aware, however, that Brian Kernighan's @command{awk}, and possibly +@code{END} rules. Be aware, however, that BWK @command{awk}, and possibly other implementations, do not. The third point follows from the first two. The meaning of @samp{print} @@ -13806,31 +13923,38 @@ case is made, the case statement bodies execute until a @code{break}, or the end of the @code{switch} statement itself. For example: @example -switch (NR * 2 + 1) @{ -case 3: -case "11": - print NR - 1 - break - -case /2[[:digit:]]+/: - print NR - -default: - print NR + 1 - -case -1: - print NR * -1 +while ((c = getopt(ARGC, ARGV, "aksx")) != -1) @{ + switch (c) @{ + case "a": + # report size of all files + all_files = TRUE; + break + case "k": + BLOCK_SIZE = 1024 # 1K block size + break + case "s": + # do sums only + sum_only = TRUE + break + case "x": + # don't cross filesystems + fts_flags = or(fts_flags, FTS_XDEV) + break + case "?": + default: + usage() + break + @} @} @end example Note that if none of the statements specified above halt execution of a matched @code{case} statement, execution falls through to the -next @code{case} until execution halts. In the above example, for -any case value starting with @samp{2} followed by one or more digits, -the @code{print} statement is executed and then falls through into the -@code{default} section, executing its @code{print} statement. In turn, -the @minus{}1 case will also be executed since the @code{default} does -not halt execution. +next @code{case} until execution halts. In the above example, the +@code{case} for @code{"?"} falls through to the @code{default} +case, which is to call a function named @code{usage()}. +(The @code{getopt()} function being called here is +described in @ref{Getopt Function}.) @node Break Statement @subsection The @code{break} Statement @@ -13904,7 +14028,7 @@ historical implementations of @command{awk} treated the @code{break} statement outside of a loop as if it were a @code{next} statement (@pxref{Next Statement}). @value{DARKCORNER} -Recent versions of Brian Kernighan's @command{awk} no longer allow this usage, +Recent versions of BWK @command{awk} no longer allow this usage, nor does @command{gawk}. @node Continue Statement @@ -13953,7 +14077,8 @@ BEGIN @{ @end example @noindent -This program loops forever once @code{x} reaches 5. +This program loops forever once @code{x} reaches 5, since +the increment (@samp{x++}) is never reached. @c @cindex @code{continue}, outside of loops @c @cindex historical features @@ -13970,7 +14095,7 @@ statement outside a loop: as if it were a @code{next} statement (@pxref{Next Statement}). @value{DARKCORNER} -Recent versions of Brian Kernighan's @command{awk} no longer work this way, nor +Recent versions of BWK @command{awk} no longer work this way, nor does @command{gawk}. @node Next Statement @@ -14059,7 +14184,8 @@ starts over with the first rule in the program. If the @code{nextfile} statement causes the end of the input to be reached, then the code in any @code{END} rules is executed. An exception to this is when @code{nextfile} is invoked during execution of any statement in an -@code{END} rule; In this case, it causes the program to stop immediately. @xref{BEGIN/END}. +@code{END} rule; in this case, it causes the program to stop immediately. +@xref{BEGIN/END}. The @code{nextfile} statement is useful when there are many @value{DF}s to process but it isn't necessary to process every record in every file. @@ -14069,13 +14195,10 @@ would have to continue scanning the unwanted records. The @code{nextfile} statement accomplishes this much more efficiently. In @command{gawk}, execution of @code{nextfile} causes additional things -to happen: -any @code{ENDFILE} rules are executed except in the case as -mentioned below, -@code{ARGIND} is incremented, -and -any @code{BEGINFILE} rules are executed. -(@code{ARGIND} hasn't been introduced yet. @xref{Built-in Variables}.) +to happen: any @code{ENDFILE} rules are executed if @command{gawk} is +not currently in an @code{END} or @code{BEGINFILE} rule, @code{ARGIND} is +incremented, and any @code{BEGINFILE} rules are executed. (@code{ARGIND} +hasn't been introduced yet. @xref{Built-in Variables}.) With @command{gawk}, @code{nextfile} is useful inside a @code{BEGINFILE} rule to skip over a file that would otherwise cause @command{gawk} @@ -14099,7 +14222,7 @@ See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @cindex @code{nextfile} statement, user-defined functions and @cindex Brian Kernighan's @command{awk} @cindex @command{mawk} utility -The current version of the Brian Kernighan's @command{awk}, and @command{mawk} (@pxref{Other +The current version of BWK @command{awk}, and @command{mawk} (@pxref{Other Versions}) also support @code{nextfile}. However, they don't allow the @code{nextfile} statement inside function bodies (@pxref{User-defined}). @command{gawk} does; a @code{nextfile} inside a function body reads the @@ -14608,7 +14731,7 @@ current record. @xref{Changing Fields}. @cindex differences in @command{awk} and @command{gawk}, @code{FUNCTAB} variable @item @code{FUNCTAB #} An array whose indices and corresponding values are the names of all -the user-defined or extension functions in the program. +the built-in, user-defined and extension functions in the program. @quotation NOTE Attempting to use the @code{delete} statement with the @code{FUNCTAB} @@ -14656,9 +14779,12 @@ text of the AWK program. For each identifier, the value of the element is one o @item "array" The identifier is an array. +@item "builtin" +The identifier is a built-in function. + @item "extension" The identifier is an extension function loaded via -@code{@@load}. +@code{@@load} or @option{-l}. @item "scalar" The identifier is a scalar. @@ -14938,7 +15064,7 @@ changed. @cindex arguments, command-line @cindex command line, arguments -@ref{Auto-set}, +@DBREF{Auto-set} presented the following program describing the information contained in @code{ARGC} and @code{ARGV}: @@ -15011,8 +15137,17 @@ before actual processing of the input begins. @xref{Split Program}, and see @ref{Tee Program}, for examples of each way of removing elements from @code{ARGV}. + +To actually get options into an @command{awk} program, +end the @command{awk} options with @option{--} and then supply +the @command{awk} program's options, in the following manner: + +@example +awk -f myprog.awk -- -v -q file1 file2 @dots{} +@end example + The following fragment processes @code{ARGV} in order to examine, and -then remove, command-line options: +then remove, the above command-line options: @example BEGIN @{ @@ -15032,32 +15167,24 @@ BEGIN @{ @} @end example -To actually get the options into the @command{awk} program, -end the @command{awk} options with @option{--} and then supply -the @command{awk} program's options, in the following manner: - -@example -awk -f myprog -- -v -q file1 file2 @dots{} -@end example - @cindex differences in @command{awk} and @command{gawk}, @code{ARGC}/@code{ARGV} variables -This is not necessary in @command{gawk}. Unless @option{--posix} has +Ending the @command{awk} options with @option{--} isn't +necessary in @command{gawk}. Unless @option{--posix} has been specified, @command{gawk} silently puts any unrecognized options into @code{ARGV} for the @command{awk} program to deal with. As soon as it sees an unknown option, @command{gawk} stops looking for other -options that it might otherwise recognize. The previous example with +options that it might otherwise recognize. The previous command line with @command{gawk} would be: @example -gawk -f myprog -q -v file1 file2 @dots{} +gawk -f myprog.awk -q -v file1 file2 @dots{} @end example @noindent -Because @option{-q} is not a valid @command{gawk} option, -it and the following @option{-v} -are passed on to the @command{awk} program. -(@xref{Getopt Function}, for an @command{awk} library function -that parses command-line options.) +Because @option{-q} is not a valid @command{gawk} option, it and the +following @option{-v} are passed on to the @command{awk} program. +(@xref{Getopt Function}, for an @command{awk} library function that +parses command-line options.) @node Pattern Action Summary @section Summary @@ -15312,7 +15439,10 @@ array element value: @end docbook @noindent -The pairs are shown in jumbled order because their order is irrelevant. +The pairs are shown in jumbled order because their order is +irrelevant.@footnote{The ordering will vary among @command{awk} +implementations, which typically use hash tables to store array elements +and values.} One advantage of associative arrays is that new pairs can be added at any time. For example, suppose a tenth element is added to the array @@ -15434,8 +15564,9 @@ English to French: Here we decided to translate the number one in both spelled-out and numeric form---thus illustrating that a single array can have both numbers and strings as indices. -(In fact, array subscripts are always strings; this is discussed -in more detail in +(In fact, array subscripts are always strings. +There are some subtleties to how numbers work when used as +array subscripts; this is discussed in more detail in @ref{Numeric Array Subscripts}.) Here, the number @code{1} isn't double-quoted, since @command{awk} automatically converts it to a string. @@ -15502,8 +15633,9 @@ if (a["foo"] != "") @dots{} @end example @noindent -This is incorrect, since this will @emph{create} @code{a["foo"]} -if it didn't exist before! +This is incorrect for two reasons. First, it @emph{creates} @code{a["foo"]} +if it didn't exist before! Second, it is valid (if a bit unusual) to set +an array element equal to the empty string. @end quotation @c @cindex arrays, @code{in} operator and @@ -15521,6 +15653,8 @@ This expression tests whether the particular index @var{indx} exists, without the side effect of creating that element if it is not present. The expression has the value one (true) if @code{@var{array}[@var{indx}]} exists and zero (false) if it does not exist. +(We use @var{indx} here, since @samp{index} is the name of a built-in +function.) For example, this statement tests whether the array @code{frequencies} contains the index @samp{2}: @@ -15728,7 +15862,7 @@ $ @kbd{gawk -f loopcheck.awk} @print{} is @end example -Contrast this to Brian Kernighan's @command{awk}: +Contrast this to BWK @command{awk}: @example $ @kbd{nawk -f loopcheck.awk} @@ -15973,7 +16107,7 @@ using @code{delete} without a subscript was a @command{gawk} extension. As of September, 2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, the Austin Group website}. This form of the @code{delete} statement is also supported -by Brian Kernighan's @command{awk} and @command{mawk}, as well as +by BWK @command{awk} and @command{mawk}, as well as by a number of other implementations (@pxref{Other Versions}). @end quotation @@ -16089,7 +16223,7 @@ $ @kbd{echo 'line 1} > @kbd{line 2} > @kbd{line 3' | awk '@{ l[lines] = $0; ++lines @}} > @kbd{END @{} -> @kbd{for (i = lines-1; i >= 0; --i)} +> @kbd{for (i = lines - 1; i >= 0; i--)} > @kbd{print l[i]} > @kbd{@}'} @print{} line 3 @@ -16113,7 +16247,7 @@ The following version of the program works correctly: @example @{ l[lines++] = $0 @} END @{ - for (i = lines - 1; i >= 0; --i) + for (i = lines - 1; i >= 0; i--) print l[i] @} @end example @@ -16187,10 +16321,11 @@ used for single dimensional arrays. Write the whole sequence of indices in parentheses, separated by commas, as the left operand: @example -(@var{subscript1}, @var{subscript2}, @dots{}) in @var{array} +if ((@var{subscript1}, @var{subscript2}, @dots{}) in @var{array}) + @dots{} @end example -The following example treats its input as a two-dimensional array of +Here is an example that treats its input as a two-dimensional array of fields; it rotates this array 90 degrees clockwise and prints the result. It assumes that all lines have the same number of elements: @@ -16663,7 +16798,9 @@ is @minus{}3, and @code{int(-3)} is @minus{}3 as well. @cindexawkfunc{log} @cindex logarithm Return the natural logarithm of @var{x}, if @var{x} is positive; -otherwise, report an error. +otherwise, return @code{NaN} (``not a number'') on IEEE 754 systems. +Additionally, @command{gawk} prints a warning message when @code{x} +is negative. @item @code{rand()} @cindexawkfunc{rand} @@ -16762,6 +16899,9 @@ numbers that are truly unpredictable. The return value of @code{srand()} is the previous seed. This makes it easy to keep track of the seeds in case you need to consistently reproduce sequences of random numbers. + +POSIX does not specify the initial seed; it differs among @command{awk} +implementations. @end table @node String Functions @@ -17437,7 +17577,7 @@ in the string, counting from character @var{start}. @cindex Brian Kernighan's @command{awk} If @var{start} is less than one, @code{substr()} treats it as if it was one. (POSIX doesn't specify what to do in this case: -Brian Kernighan's @command{awk} acts this way, and therefore @command{gawk} +BWK @command{awk} acts this way, and therefore @command{gawk} does too.) If @var{start} is greater than the number of characters in the string, @code{substr()} returns the null string. @@ -17506,6 +17646,12 @@ Nonalphabetic characters are left unchanged. For example, @cindex backslash (@code{\}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @cindex @code{&} (ampersand), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @cindex ampersand (@code{&}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and + +@quotation CAUTION +This section has been known to cause headaches. +You might want to skip it upon first reading. +@end quotation + When using @code{sub()}, @code{gsub()}, or @code{gensub()}, and trying to get literal backslashes and ampersands into the replacement text, you need to remember that there are several levels of @dfn{escape processing} going on. @@ -17523,7 +17669,7 @@ escape sequences listed in @ref{Escape Sequences}. Thus, for every @samp{\} that @command{awk} processes at the runtime level, you must type two backslashes at the lexical level. When a character that is not valid for an escape sequence follows the -@samp{\}, Brian Kernighan's @command{awk} and @command{gawk} both simply remove the initial +@samp{\}, BWK @command{awk} and @command{gawk} both simply remove the initial @samp{\} and put the next character into the string. Thus, for example, @code{"a\qb"} is treated as @code{"aqb"}. @@ -17548,26 +17694,26 @@ through unchanged. This is illustrated in @ref{table-sub-escapes}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr - @code{\&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\\&}! @code{\\&}!a literal @samp{\&}_cr - @code{\\\\\&}! @code{\\&}!a literal @samp{\&}_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\\&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr + @code{\&}! @code{&}!The matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\\&}! @code{\\&}!A literal @samp{\&}_cr + @code{\\\\\&}! @code{\\&}!A literal @samp{\&}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\\&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr } _bigskip} @end tex @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\&} -@item @code{\\\\\&} @tab @code{\\&} @tab a literal @samp{\&} -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\\&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\&} @tab @code{&} @tab The matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\&} +@item @code{\\\\\&} @tab @code{\\&} @tab A literal @samp{\&} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\\&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @end multitable @end ifdocbook @ifnottex @@ -17575,13 +17721,13 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- - @code{\&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\&} @code{\&} a literal @samp{&} - @code{\\\\&} @code{\\&} a literal @samp{\&} - @code{\\\\\&} @code{\\&} a literal @samp{\&} -@code{\\\\\\&} @code{\\\&} a literal @samp{\\&} - @code{\\q} @code{\q} a literal @samp{\q} + @code{\&} @code{&} The matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\\&} @code{\&} A literal @samp{&} + @code{\\\\&} @code{\\&} A literal @samp{\&} + @code{\\\\\&} @code{\\&} A literal @samp{\&} +@code{\\\\\\&} @code{\\\&} A literal @samp{\\&} + @code{\\q} @code{\q} A literal @samp{\q} @end display @end ifnotdocbook @end ifnottex @@ -17597,86 +17743,19 @@ case of even numbers of backslashes entered at the lexical level.) The problem with the historical approach is that there is no way to get a literal @samp{\} followed by the matched text. -@c @cindex @command{awk} language, POSIX version -@cindex POSIX @command{awk}, functions and, @code{gsub()}/@code{sub()} -The 1992 POSIX standard attempted to fix this problem. That standard -says that @code{sub()} and @code{gsub()} look for either a @samp{\} or an @samp{&} -after the @samp{\}. If either one follows a @samp{\}, that character is -output literally. The interpretation of @samp{\} and @samp{&} then becomes -as shown in @ref{table-sub-posix-92}. - -@float Table,table-sub-posix-92 -@caption{1992 POSIX Rules for @code{sub()} and @code{gsub()} Escape Sequence Processing} -@c thanks to Karl Berry for formatting this table -@tex -\vbox{\bigskip -% We need more characters for escape and tab ... -\catcode`_ = 0 -\catcode`! = 4 -% ... since this table has lots of &'s and \'s, so we unspecialize them. -\catcode`\& = \other \catcode`\\ = \other -_halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr - You type!@code{sub()} sees!@code{sub()} generates_cr -_hrulefill!_hrulefill!_hrulefill_cr - @code{&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, then the matched text_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -} -_bigskip} -@end tex -@ifdocbook -@multitable @columnfractions .20 .20 .60 -@headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, then the matched text -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@end multitable -@end ifdocbook -@ifnottex -@ifnotdocbook -@display - You type @code{sub()} sees @code{sub()} generates - -------- ---------- --------------- - @code{&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\\&} @code{\\&} a literal @samp{\}, then the matched text -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} -@end display -@end ifnotdocbook -@end ifnottex -@end float - -@noindent -This appears to solve the problem. -Unfortunately, the phrasing of the standard is unusual. It -says, in effect, that @samp{\} turns off the special meaning of any -following character, but for anything other than @samp{\} and @samp{&}, -such special meaning is undefined. This wording leads to two problems: - -@itemize @value{BULLET} -@item -Backslashes must now be doubled in the @var{replacement} string, breaking -historical @command{awk} programs. - -@item -To make sure that an @command{awk} program is portable, @emph{every} character -in the @var{replacement} string must be preceded with a -backslash.@footnote{This consequence was certainly unintended.} -@c I can say that, 'cause I was involved in making this change -@end itemize +Several editions of the POSIX standard attempted to fix this problem +but weren't successful. The details are irrelevant at this point in time. -Because of the problems just listed, -in 1996, the @command{gawk} maintainer submitted +At one point, the @command{gawk} maintainer submitted proposed text for a revised standard that reverts to rules that correspond more closely to the original existing practice. The proposed rules have special cases that make it possible -to produce a @samp{\} preceding the matched text. This is shown in +to produce a @samp{\} preceding the matched text. +This is shown in @ref{table-sub-proposed}. @float Table,table-sub-proposed -@caption{Proposed Rules For @code{sub()} And Backslash} +@caption{GNU @command{awk} Rules For @code{sub()} And Backslash} @tex \vbox{\bigskip % We need more characters for escape and tab ... @@ -17687,10 +17766,10 @@ to produce a @samp{\} preceding the matched text. This is shown in _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, followed by the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr +@code{\\\\&}! @code{\\&}!A literal @samp{\}, followed by the matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr @code{\\\\}! @code{\\}!@code{\\}_cr } _bigskip} @@ -17698,10 +17777,10 @@ _bigskip} @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, followed by the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, followed by the matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @item @code{\\\\} @tab @code{\\} @tab @code{\\} @end multitable @end ifdocbook @@ -17710,10 +17789,10 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\\\&} @code{\\&} a literal @samp{\}, followed by the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\q} @code{\q} a literal @samp{\q} +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\\\&} @code{\\&} A literal @samp{\}, followed by the matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\q} @code{\q} A literal @samp{\q} @code{\\\\} @code{\\} @code{\\} @end display @end ifnotdocbook @@ -17726,13 +17805,13 @@ there was only one. However, as in the historical case, any @samp{\} that is not part of one of these three sequences is not special and appears in the output literally. -@command{gawk} 3.0 and 3.1 follow these proposed POSIX rules for @code{sub()} and -@code{gsub()}. -@c As much as we think it's a lousy idea. You win some, you lose some. Sigh. -The POSIX standard took much longer to be revised than was expected in 1996. -The 2001 standard does not follow the above rules. Instead, the rules -there are somewhat simpler. The results are similar except for one case. +@command{gawk} 3.0 and 3.1 follow these rules for @code{sub()} and +@code{gsub()}. The POSIX standard took much longer to be revised than +was expected. In addition, the @command{gawk} maintainer's proposal was +lost during the standardization process. The final rules are +somewhat simpler. The results are similar except for one case. +@cindex POSIX @command{awk}, functions and, @code{gsub()}/@code{sub()} The POSIX rules state that @samp{\&} in the replacement string produces a literal @samp{&}, @samp{\\} produces a literal @samp{\}, and @samp{\} followed by anything else is not special; the @samp{\} is placed straight into the output. @@ -17750,10 +17829,10 @@ These rules are presented in @ref{table-posix-sub}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, followed by the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr +@code{\\\\&}! @code{\\&}!A literal @samp{\}, followed by the matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr @code{\\\\}! @code{\\}!@code{\}_cr } _bigskip} @@ -17761,10 +17840,10 @@ _bigskip} @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, followed by the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, followed by the matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @item @code{\\\\} @tab @code{\\} @tab @code{\} @end multitable @end ifdocbook @@ -17773,10 +17852,10 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\\\&} @code{\\&} a literal @samp{\}, followed by the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\q} @code{\q} a literal @samp{\q} +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\\\&} @code{\\&} A literal @samp{\}, followed by the matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\q} @code{\q} A literal @samp{\q} @code{\\\\} @code{\\} @code{\} @end display @end ifnotdocbook @@ -17788,7 +17867,7 @@ is seen as @samp{\\} and produces @samp{\} instead of @samp{\\}. Starting with @value{PVERSION} 3.1.4, @command{gawk} followed the POSIX rules when @option{--posix} is specified (@pxref{Options}). Otherwise, -it continued to follow the 1996 proposed rules, since +it continued to follow the proposed rules, since that had been its behavior for many years. When @value{PVERSION} 4.0.0 was released, the @command{gawk} maintainer @@ -17819,24 +17898,24 @@ as shown in @ref{table-gensub-escapes}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{gensub()} sees!@code{gensub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr - @code{&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\\}! @code{\\}!a literal @samp{\}_cr - @code{\\\\&}! @code{\\&}!a literal @samp{\}, then the matched text_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr - @code{\\q}! @code{\q}!a literal @samp{q}_cr + @code{&}! @code{&}!The matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\\}! @code{\\}!A literal @samp{\}_cr + @code{\\\\&}! @code{\\&}!A literal @samp{\}, then the matched text_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr + @code{\\q}! @code{\q}!A literal @samp{q}_cr } _bigskip} @end tex @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{gensub()} sees @tab @code{gensub()} generates -@item @code{&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\} @tab @code{\\} @tab a literal @samp{\} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, then the matched text -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{q} +@item @code{&} @tab @code{&} @tab The matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\\} @tab @code{\\} @tab A literal @samp{\} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, then the matched text +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{q} @end multitable @end ifdocbook @ifnottex @@ -17844,12 +17923,12 @@ _bigskip} @display You type @code{gensub()} sees @code{gensub()} generates -------- ------------- ------------------ - @code{&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\\} @code{\\} a literal @samp{\} - @code{\\\\&} @code{\\&} a literal @samp{\}, then the matched text -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\q} @code{\q} a literal @samp{q} + @code{&} @code{&} The matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\\\} @code{\\} A literal @samp{\} + @code{\\\\&} @code{\\&} A literal @samp{\}, then the matched text +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\q} @code{\q} A literal @samp{q} @end display @end ifnotdocbook @end ifnottex @@ -17964,7 +18043,7 @@ buffers its output and the @code{fflush()} function forces @cindex extensions, common@comma{} @code{fflush()} function @cindex Brian Kernighan's @command{awk} -@code{fflush()} was added to Brian Kernighan's @command{awk} in +@code{fflush()} was added to BWK @command{awk} in April of 1992. For two decades, it was not part of the POSIX standard. As of December, 2012, it was accepted for inclusion into the POSIX standard. @@ -19081,6 +19160,12 @@ them, i.e., to tell @command{awk} what they should do. @node Definition Syntax @subsection Function Definition Syntax +@quotation +It's entirely fair to say that the @command{awk} syntax for local +variable definitions is appallingly awful. +@author Brian Kernighan +@end quotation + @c STARTOFRANGE fdef @cindex functions, defining Definitions of functions can appear anywhere between the rules of an @@ -19120,7 +19205,7 @@ have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters cannot have the same name as one of the special built-in variables (@pxref{Built-in Variables}). Not all versions of @command{awk} enforce -this restriction.) +this restriction. Local variables act like the empty string if referenced where a string value is required, and like zero if referenced where a numeric value @@ -19250,7 +19335,8 @@ this program, using our function to format the results, prints: 21.2 @end example -This function deletes all the elements in an array: +This function deletes all the elements in an array (recall that the +extra whitespace signifies the start of the local variable list): @example function delarray(a, i) @@ -19273,17 +19359,18 @@ addition to the POSIX standard.) The following is an example of a recursive function. It takes a string as an input parameter and returns the string in backwards order. Recursive functions must always have a test that stops the recursion. -In this case, the recursion terminates when the starting position -is zero, i.e., when there are no more characters left in the string. +In this case, the recursion terminates when the input string is +already empty. +@c 8/2014: Thanks to Mike Brennan for the improved formulation @cindex @code{rev()} user-defined function @example -function rev(str, start) +function rev(str) @{ - if (start == 0) + if (str == "") return "" - return (substr(str, start, 1) rev(str, start - 1)) + return (rev(substr(str, 2)) substr(str, 1, 1)) @} @end example @@ -19292,7 +19379,7 @@ this way: @example $ @kbd{echo "Don't Panic!" |} -> @kbd{gawk --source '@{ print rev($0, length($0)) @}' -f rev.awk} +> @kbd{gawk -e '@{ print rev($0) @}' -f rev.awk} @print{} !cinaP t'noD @end example @@ -19577,7 +19664,7 @@ BEGIN @{ @noindent prints @samp{a[1] = 1, a[2] = two, a[3] = 3}, because -@code{changeit} stores @code{"two"} in the second element of @code{a}. +@code{changeit()} stores @code{"two"} in the second element of @code{a}. @end quotation @cindex undefined functions @@ -19753,7 +19840,7 @@ being aware of them. @cindex pointers to functions @cindex differences in @command{awk} and @command{gawk}, indirect function calls -This section describes a @command{gawk}-specific extension. +This section describes an advanced, @command{gawk}-specific extension. Often, you may wish to defer the choice of function to call until runtime. For example, you may have different kinds of records, each of which @@ -19799,8 +19886,11 @@ To process the data, you might write initially: @noindent This style of programming works, but can be awkward. With @dfn{indirect} function calls, you tell @command{gawk} to use the @emph{value} of a -variable as the name of the function to call. +variable as the @emph{name} of the function to call. +@cindex @code{@@}-notation for indirect function calls +@cindex indirect function calls, @code{@@}-notation +@cindex function calls, indirect, @code{@@}-notation for The syntax is similar to that of a regular function call: an identifier immediately followed by a left parenthesis, any arguments, and then a closing right parenthesis, with the addition of a leading @samp{@@} @@ -19858,7 +19948,6 @@ Otherwise they perform the expected computations and are not unusual. @example @c file eg/prog/indirectcall.awk # For each record, print the class name and the requested statistics - @{ class_name = $1 gsub(/_/, " ", class_name) # Replace _ with spaces @@ -20087,10 +20176,12 @@ $ @kbd{gawk -f quicksort.awk -f indirectcall.awk class_data2} Remember that you must supply a leading @samp{@@} in front of an indirect function call. -Unfortunately, indirect function calls cannot be used with the built-in functions. However, -you can generally write ``wrapper'' functions which call the built-in ones, and those can -be called indirectly. (Other than, perhaps, the mathematical functions, there is not a lot -of reason to try to call the built-in functions indirectly.) +Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function +calls may also be used with built-in functions and with extension functions +(@pxref{Dynamic Extensions}). The only thing you cannot do is pass a regular +expression constant to a built-in function through an indirect function +call.@footnote{This may change in a future version; recheck the documentation that +comes with your version of @command{gawk} to see if it has.} @command{gawk} does its best to make indirect function calls efficient. For example, in the following case: @@ -20101,7 +20192,7 @@ for (i = 1; i <= n; i++) @end example @noindent -@code{gawk} will look up the actual function to call only once. +@code{gawk} looks up the actual function to call only once. @node Functions Summary @section Summary @@ -20141,6 +20232,8 @@ from the real parameters by extra whitespace. User-defined functions may call other user-defined (and built-in) functions and may call themselves recursively. Function parameters ``hide'' any global variables of the same names. +You cannot use the name of a reserved variable (such as @code{ARGC}) +as the name of a parameter in user-defined functions. @item Scalar values are passed to user-defined functions by value. Array @@ -20159,7 +20252,7 @@ either scalar or array. @item @command{gawk} provides indirect function calls using a special syntax. -By setting a variable to the name of a user-defined function, you can +By setting a variable to the name of a function, you can determine at runtime what function will be called at that point in the program. This is equivalent to function pointers in C and C++. @@ -20194,7 +20287,7 @@ It contains the following chapters: @c STARTOFRANGE fudlib @cindex functions, user-defined, library of -@ref{User-defined}, describes how to write +@DBREF{User-defined} describes how to write your own @command{awk} functions. Writing functions is important, because it allows you to encapsulate algorithms and program tasks in a single place. It simplifies programming, making program development more @@ -20218,7 +20311,7 @@ of good programs leads to better writing. In fact, they felt this idea was so important that they placed this statement on the cover of their book. Because we believe strongly that their statement is correct, this @value{CHAPTER} and @ref{Sample -Programs}, provide a good-sized body of code for you to read, and we hope, +Programs}, provide a good-sized body of code for you to read and, we hope, to learn from. This @value{CHAPTER} presents a library of useful @command{awk} functions. @@ -20227,7 +20320,7 @@ use these functions. The functions are presented here in a progression from simple to complex. @cindex Texinfo -@ref{Extract Program}, +@DBREF{Extract Program} presents a program that you can use to extract the source code for these example library functions and programs from the Texinfo source for this @value{DOCUMENT}. @@ -20291,7 +20384,7 @@ comparisons use only lowercase letters. * Group Functions:: Functions for getting group information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. @end menu @node Library Names @@ -20378,7 +20471,7 @@ A different convention, common in the Tcl community, is to use a single associative array to hold the values needed by the library function(s), or ``package.'' This significantly decreases the number of actual global names in use. For example, the functions described in -@ref{Passwd Functions}, +@DBREF{Passwd Functions} might have used array elements @code{@w{PW_data["inited"]}}, @code{@w{PW_data["total"]}}, @code{@w{PW_data["count"]}}, and @code{@w{PW_data["awklib"]}}, instead of @code{@w{_pw_inited}}, @code{@w{_pw_awklib}}, @code{@w{_pw_total}}, @@ -20439,8 +20532,9 @@ function mystrtonum(str, ret, n, i, k, c) ret = 0 for (i = 1; i <= n; i++) @{ c = substr(str, i, 1) - if ((k = index("01234567", c)) > 0) - k-- # adjust for 1-basing in awk + # index() returns 0 if c not in string, + # includes c == "0" + k = index("1234567", c) ret = ret * 8 + k @} @@ -20452,6 +20546,8 @@ function mystrtonum(str, ret, n, i, k, c) for (i = 1; i <= n; i++) @{ c = substr(str, i, 1) c = tolower(c) + # index() returns 0 if c not in string, + # includes c == "0" k = index("123456789abcdef", c) ret = ret * 16 + k @@ -20853,8 +20949,7 @@ function chr(c) @c endfile #### test code #### -# BEGIN \ -# @{ +# BEGIN @{ # for (;;) @{ # printf("enter a character: ") # if (getline var <= 0) @@ -20939,7 +21034,7 @@ more difficult than they really need to be.} @cindex timestamps, formatted @cindex time, managing The @code{systime()} and @code{strftime()} functions described in -@ref{Time Functions}, +@DBREF{Time Functions} provide the minimum functionality necessary for dealing with the time of day in human readable form. While @code{strftime()} is extensive, the control formats are not necessarily easy to remember or intuitively obvious when @@ -21025,7 +21120,7 @@ function getlocaltime(time, ret, now, i) The string indices are easier to use and read than the various formats required by @code{strftime()}. The @code{alarm} program presented in -@ref{Alarm Program}, +@DBREF{Alarm Program} uses this function. A more general design for the @code{getlocaltime()} function would have allowed the user to supply an optional timestamp value to use instead @@ -21228,7 +21323,7 @@ END @{ endfile(_filename_) @} @c endfile @end example -@ref{Wc Program}, +@DBREF{Wc Program} shows how this library function can be used and how it simplifies writing the main program. @@ -21728,8 +21823,7 @@ it is not an option, and it ends option processing. Continuing on: i = index(options, thisopt) if (i == 0) @{ if (Opterr) - printf("%c -- invalid option\n", - thisopt) > "/dev/stderr" + printf("%c -- invalid option\n", thisopt) > "/dev/stderr" if (_opti >= length(argv[Optind])) @{ Optind++ _opti = 0 @@ -22232,7 +22326,7 @@ once. If you are worried about squeezing every last cycle out of your this is not necessary, since most @command{awk} programs are I/O-bound, and such a change would clutter up the code. -The @command{id} program in @ref{Id Program}, +The @command{id} program in @DBREF{Id Program} uses these functions. @c ENDOFRANGE libfudata @c ENDOFRANGE flibudata @@ -22258,7 +22352,7 @@ uses these functions. @cindex group file @cindex files, group Much of the discussion presented in -@ref{Passwd Functions}, +@DBREF{Passwd Functions} applies to the group database as well. Although there has traditionally been a well-known file (@file{/etc/group}) in a well-known format, the POSIX standard only provides a set of C library routines @@ -22411,8 +22505,7 @@ There are several, modeled after the C library functions of the same names: @c line break on _gr_init for smallbook @c file eg/lib/groupawk.in -BEGIN \ -@{ +BEGIN @{ # Change to suit your system _gr_awklib = "/usr/local/libexec/awk/" @} @@ -22598,13 +22691,13 @@ Most of the work is in scanning the database and building the various associative arrays. The functions that the user calls are themselves very simple, relying on @command{awk}'s associative arrays to do work. -The @command{id} program in @ref{Id Program}, +The @command{id} program in @DBREF{Id Program} uses these functions. @node Walking Arrays @section Traversing Arrays of Arrays -@ref{Arrays of Arrays}, described how @command{gawk} +@DBREF{Arrays of Arrays} described how @command{gawk} provides arrays of arrays. In particular, any element of an array may be either a scalar, or another array. The @code{isarray()} function (@pxref{Type Functions}) @@ -22710,7 +22803,8 @@ A simple function to traverse an array of arrays to any depth. @end itemize -@node Library exercises +@c EXCLUDE START +@node Library Exercises @section Exercises @enumerate @@ -22758,7 +22852,7 @@ As a related challenge, revise that code to handle the case where an intervening value in @code{ARGV} is a variable assignment. @item -@ref{Walking Arrays}, presented a function that walked a multidimensional +@DBREF{Walking Arrays} presented a function that walked a multidimensional array to print it out. However, walking an array and processing each element is a general-purpose operation. Generalize the @code{walk_array()} function by adding an additional parameter named @@ -22776,6 +22870,7 @@ Test your new version by printing the array; you should end up with output identical to that of the original version. @end enumerate +@c EXCLUDE END @c ENDOFRANGE flib @c ENDOFRANGE fudlib @@ -22989,8 +23084,7 @@ string: @example @c file eg/prog/cut.awk -BEGIN \ -@{ +BEGIN @{ FS = "\t" # default OFS = FS while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) @{ @@ -23465,8 +23559,7 @@ there are no matches, the exit status is one; otherwise it is zero: @example @c file eg/prog/egrep.awk -END \ -@{ +END @{ exit (total == 0) @} @c endfile @@ -23490,17 +23583,6 @@ function usage( e) The variable @code{e} is used so that the function fits nicely on the printed page. -@cindex @code{END} pattern, backslash continuation and -@cindex @code{\} (backslash), continuing lines and -@cindex backslash (@code{\}), continuing lines and -Just a note on programming style: you may have noticed that the @code{END} -rule uses backslash continuation, with the open brace on a line by -itself. This is so that it more closely resembles the way functions -are written. Many of the examples -in this @value{CHAPTER} -use this style. You can decide for yourself if you like writing -your @code{BEGIN} and @code{END} rules this way -or not. @c ENDOFRANGE regexps @c ENDOFRANGE sfregexp @c ENDOFRANGE fsregexp @@ -23567,8 +23649,7 @@ numbers: # egid=5(blat) groups=9(nine),2(two),1(one) @group -BEGIN \ -@{ +BEGIN @{ uid = PROCINFO["uid"] euid = PROCINFO["euid"] gid = PROCINFO["gid"] @@ -23785,6 +23866,12 @@ instead of doing it in an @code{END} rule. It also assumes that letters are contiguous in the character set, which isn't true for EBCDIC systems. +@ifset FOR_PRINT +You might want to consider how to eliminate the use of +@code{ord()} and @code{chr()}; this can be done in such a +way as to solve the EBCDIC issue as well. +@end ifset + @c ENDOFRANGE filspl @c ENDOFRANGE split @@ -23838,8 +23925,7 @@ Finally, @command{awk} is forced to read the standard input by setting @c endfile @end ignore @c file eg/prog/tee.awk -BEGIN \ -@{ +BEGIN @{ for (i = 1; i < ARGC; i++) copy[i] = ARGV[i] @@ -23901,8 +23987,7 @@ Finally, the @code{END} rule cleans up by closing all the output files: @example @c file eg/prog/tee.awk -END \ -@{ +END @{ for (i in copy) close(copy[i]) @} @@ -24019,8 +24104,7 @@ function usage( e) # -n skip n fields # +n skip n characters, skip fields first -BEGIN \ -@{ +BEGIN @{ count = 1 outputfile = "/dev/stdout" opts = "udc0:1:2:3:4:5:6:7:8:9:" @@ -24032,7 +24116,7 @@ BEGIN \ else if (c == "c") do_count++ else if (index("0123456789", c) != 0) @{ - # getopt requires args to options + # getopt() requires args to options # this messes us up for things like -5 if (Optarg ~ /^[[:digit:]]+$/) fcount = (c Optarg) + 0 @@ -24169,6 +24253,22 @@ END @{ @} @c endfile @end example + +@ifset FOR_PRINT +The logic for choosing which lines to print represents a @dfn{state +machine}, which is ``a device that can be in one of a set number of stable +conditions depending on its previous condition and on the present values +of its inputs.''@footnote{This is the definition returned from entering +@code{define: state machine} into Google.} +Brian Kernighan suggests that +``an alternative approach to state mechines is to just read +the input into an array, then use indexing. It's almost always +easier code, and for most inputs where you would use this, just +as fast.'' Consider how to rewrite the logic to follow this +suggestion. +@end ifset + + @c ENDOFRANGE prunt @c ENDOFRANGE tpul @c ENDOFRANGE uniq @@ -24539,8 +24639,7 @@ Here is the program: @c file eg/prog/alarm.awk # usage: alarm time [ "message" [ count [ delay ] ] ] -BEGIN \ -@{ +BEGIN @{ # Initial argument sanity checking usage1 = "usage: alarm time ['message' [count [delay]]]" usage2 = sprintf("\t(%s) time ::= hh:mm", ARGV[1]) @@ -24695,7 +24794,7 @@ of standard @command{awk}: dealing with individual characters is very painful, requiring repeated use of the @code{substr()}, @code{index()}, and @code{gsub()} built-in functions (@pxref{String Functions}).@footnote{This -program was written before @command{gawk} acquired the ability to +program was also written before @command{gawk} acquired the ability to split each character in a string into separate array elements.} There are two functions. The first, @code{stranslate()}, takes three arguments: @@ -24803,6 +24902,12 @@ An obvious improvement to this program would be to set up the @code{t_ar} array only once, in a @code{BEGIN} rule. However, this assumes that the ``from'' and ``to'' lists will never change throughout the lifetime of the program. + +Another obvious improvement is to enable the use of ranges, +such as @samp{a-z}, as allowed by the @command{tr} utility. +Look at the code for @file{cut.awk} (@pxref{Cut Program}) +for inspiration. + @c ENDOFRANGE chtra @c ENDOFRANGE tr @@ -24935,8 +25040,7 @@ function printpage( i, j) Count++ @} -END \ -@{ +END @{ printpage() @} @c endfile @@ -25587,7 +25691,7 @@ a shell variable that will be expanded. There are two cases: @enumerate a @item -Literal text, provided with @option{--source} or @option{--source=}. This +Literal text, provided with @option{-e} or @option{--source}. This text is just appended directly. @item @@ -25932,7 +26036,7 @@ The program should exit without reading any @value{DF}s. However, suppose that an included library file defines an @code{END} rule of its own. In this case, @command{gawk} will hang, reading standard input. In order to avoid this, @file{/dev/null} is explicitly added to the -command-line. Reading from @file{/dev/null} always returns an immediate +command line. Reading from @file{/dev/null} always returns an immediate end of file indication. @c Hmm. Add /dev/null if $# is 0? Still messes up ARGV. Sigh. @@ -26275,6 +26379,7 @@ mailing labels, and finding anagrams. @end itemize +@c EXCLUDE START @node Programs Exercises @section Exercises @@ -26298,17 +26403,27 @@ information is printed. Modify the @command{awk} version same way. @item -The @code{split.awk} program (@pxref{Split Program}) uses -the @code{chr()} and @code{ord()} functions to move through the -letters of the alphabet. -Modify the program to instead use only the @command{awk} -built-in functions, such as @code{index()} and @code{substr()}. - -@item The @code{split.awk} program (@pxref{Split Program}) assumes that letters are contiguous in the character set, which isn't true for EBCDIC systems. Fix this problem. +(Hint: Consider a different way to work through the alphabet, +without relying on @code{ord()} and @code{chr()}.) + +@item +In @file{uniq.awk} (@pxref{Uniq Program}, the +logic for choosing which lines to print represents a @dfn{state +machine}, which is ``a device that can be in one of a set number of stable +conditions depending on its previous condition and on the present values +of its inputs.''@footnote{This is the definition returned from entering +@code{define: state machine} into Google.} +Brian Kernighan suggests that +``an alternative approach to state mechines is to just read +the input into an array, then use indexing. It's almost always +easier code, and for most inputs where you would use this, just +as fast.'' Rewrite the logic to follow this +suggestion. + @item Why can't the @file{wc.awk} program (@pxref{Wc Program}) just @@ -26404,6 +26519,7 @@ Modify @file{anagram.awk} (@pxref{Anagram Program}), to avoid the use of the external @command{sort} utility. @end enumerate +@c EXCLUDE END @ifnotinfo @part @value{PART3}Moving Beyond Standard @command{awk} With @command{gawk} @@ -26585,7 +26701,7 @@ Often, though, it is desirable to be able to loop over the elements in a particular order that you, the programmer, choose. @command{gawk} lets you do this. -@ref{Controlling Scanning}, describes how you can assign special, +@DBREF{Controlling Scanning} describes how you can assign special, pre-defined values to @code{PROCINFO["sorted_in"]} in order to control the order in which @command{gawk} traverses an array during a @code{for} loop. @@ -26954,6 +27070,9 @@ Caveat Emptor. @node Two-way I/O @section Two-Way Communications with Another Process + +@c 8/2014. Neither Mike nor BWK saw this as relevant. Commenting it out. +@ignore @cindex Brennan, Michael @cindex programmers, attractiveness of @smallexample @@ -26983,6 +27102,7 @@ the scent of perl programmers. Mike Brennan @c brennan@@whidbey.com @end smallexample +@end ignore @cindex advanced features, processes@comma{} communicating with @cindex processes, two-way communications with @@ -27009,7 +27129,10 @@ system("rm " tempfile) This works, but not elegantly. Among other things, it requires that the program be run in a directory that cannot be shared among users; for example, @file{/tmp} will not do, as another user might happen -to be using a temporary file with the same name. +to be using a temporary file with the same name.@footnote{Michael +Brennan suggests the use of @command{rand()} to generate unique +@value{FN}s. This is a valid point; nevertheless, temporary files +remain more difficult than two-way pipes.} @c 8/2014 @cindex coprocesses @cindex input/output, two-way @@ -27164,7 +27287,7 @@ You can think of this as just a @emph{very long} two-way pipeline to a coprocess. The way @command{gawk} decides that you want to use TCP/IP networking is by recognizing special @value{FN}s that begin with one of @samp{/inet/}, -@samp{/inet4/} or @samp{/inet6}. +@samp{/inet4/} or @samp{/inet6/}. The full syntax of the special @value{FN} is @file{/@var{net-type}/@var{protocol}/@var{local-port}/@var{remote-host}/@var{remote-port}}. @@ -27815,7 +27938,16 @@ and/or groups of characters sort in a given language. @cindex @code{LC_CTYPE} locale category @item LC_CTYPE Character-type information (alphabetic, digit, upper- or lowercase, and -so on). +so on) as well as character encoding. +@ignore +In June 2001 Bruno Haible wrote: +- Description of LC_CTYPE: It determines both + 1. character encoding, + 2. character type information. + (For example, in both KOI8-R and ISO-8859-5 the character type information + is the same - cyrillic letters could as 'alpha' - but the encoding is + different.) +@end ignore This information is accessed via the POSIX character classes in regular expressions, such as @code{/[[:alnum:]]/} @@ -27836,11 +27968,6 @@ use a comma every three decimal places and a period for the decimal point, while many Europeans do exactly the opposite: 1,234.56 versus 1.234,56.} -@cindex @code{LC_RESPONSE} locale category -@item LC_RESPONSE -Response information, such as how ``yes'' and ``no'' appear in the -local language, and possibly other information as well. - @cindex time, localization and @cindex dates, information related to@comma{} localization @cindex @code{LC_TIME} locale category @@ -27975,18 +28102,33 @@ printf(_"Number of users is %d\n", nusers) @item If you are creating strings dynamically, you can still translate them, using the @code{dcgettext()} -built-in function: +built-in function:@footnote{Thanks to Bruno Haible for this +example.} @example -message = nusers " users logged in" -message = dcgettext(message, "adminprog") -print message +if (groggy) + message = dcgettext("%d customers disturbing me\n", "adminprog") +else + message = dcgettext("enjoying %d customers\n", "adminprog") +printf(message, ncustomers) @end example Here, the call to @code{dcgettext()} supplies a different text domain (@code{"adminprog"}) in which to find the message, but it uses the default @code{"LC_MESSAGES"} category. +The previous example only works if @code{ncustomers} is greater than one. +This example would be better done with @code{dcngettext()}: + +@example +if (groggy) + message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") +else + message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") +printf(message, ncustomers) +@end example + + @cindex @code{LC_MESSAGES} locale category, @code{bindtextdomain()} function (@command{gawk}) @item During development, you might want to put the @file{.gmo} @@ -28066,6 +28208,9 @@ appear as the first argument to @code{dcgettext()} or as the first and second argument to @code{dcngettext()}.@footnote{The @command{xgettext} utility that comes with GNU @command{gettext} can handle @file{.awk} files.} +You should distribute the generated @file{.pot} file with +your @command{awk} program; translators will eventually use it +to provide you translations that you can also then distribute. @xref{I18N Example}, for the full list of steps to go through to create and test translations for @command{guide}. @@ -28356,8 +28501,7 @@ This file must be renamed and placed in the proper directory so that @command{gawk} can find it: @example -$ @kbd{msgfmt guide-mellow.po} -$ @kbd{mv messages en_US.UTF-8/LC_MESSAGES/guide.mo} +$ @kbd{msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo} @end example Finally, we run the program to test it: @@ -28624,7 +28768,7 @@ to debug command-line programs, only programs contained in files.) In our case, we invoke the debugger like this: @example -$ @kbd{gawk -D -f getopt.awk -f join.awk -f uniq.awk inputfile} +$ @kbd{gawk -D -f getopt.awk -f join.awk -f uniq.awk -1 inputfile} @end example @noindent @@ -28686,7 +28830,7 @@ the breakpoint, use the @code{b} (breakpoint) command: @example gawk> @kbd{b are_equal} -@print{} Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 64 +@print{} Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 63 @end example The debugger tells us the file and line number where the breakpoint is. @@ -28698,8 +28842,8 @@ gawk> @kbd{r} @print{} Starting program: @print{} Stopping in Rule ... @print{} Breakpoint 1, are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':64 -@print{} 64 if (fcount == 0 && charcount == 0) + at `awklib/eg/prog/uniq.awk':63 +@print{} 63 if (fcount == 0 && charcount == 0) gawk> @end example @@ -28711,12 +28855,12 @@ listing of the current stack frames: @example gawk> @kbd{bt} @print{} #0 are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':69 -@print{} #1 in main() at `awklib/eg/prog/uniq.awk':89 + at `awklib/eg/prog/uniq.awk':68 +@print{} #1 in main() at `awklib/eg/prog/uniq.awk':88 @end example This tells us that @code{are_equal()} was called by the main program at -line 89 of @file{uniq.awk}. (This is not a big surprise, since this +line 88 of @file{uniq.awk}. (This is not a big surprise, since this is the only call to @code{are_equal()} in the program, but in more complex programs, knowing who called a function and with what parameters can be the key to finding the source of the problem.) @@ -28740,7 +28884,7 @@ A more useful variable to display might be the current record: @example gawk> @kbd{p $0} -@print{} $0 = string ("gawk is a wonderful program!") +@print{} $0 = "gawk is a wonderful program!" @end example @noindent @@ -28749,7 +28893,7 @@ our test input above. Let's look at @code{NR}: @example gawk> @kbd{p NR} -@print{} NR = number (2) +@print{} NR = 2 @end example @noindent @@ -28768,7 +28912,7 @@ OK, let's just check that that rule worked correctly: @example gawk> @kbd{p last} -@print{} last = string ("awk is a wonderful program!") +@print{} last = "awk is a wonderful program!" @end example Everything we have done so far has verified that the program has worked as @@ -28779,13 +28923,13 @@ be inside this function. To investigate further, we must begin @example gawk> @kbd{n} -@print{} 67 if (fcount > 0) @{ +@print{} 66 if (fcount > 0) @{ @end example -This tells us that @command{gawk} is now ready to execute line 67, which +This tells us that @command{gawk} is now ready to execute line 66, which decides whether to give the lines the special ``field skipping'' treatment -indicated by the @option{-f} command-line option. (Notice that we skipped -from where we were before at line 64 to here, since the condition in line 64 +indicated by the @option{-1} command-line option. (Notice that we skipped +from where we were before at line 63 to here, since the condition in line 63 @samp{if (fcount == 0 && charcount == 0)} was false.) Continuing to step, we now get to the splitting of the current and @@ -28793,9 +28937,9 @@ last records: @example gawk> @kbd{n} -@print{} 68 n = split(last, alast) +@print{} 67 n = split(last, alast) gawk> @kbd{n} -@print{} 69 m = split($0, aline) +@print{} 68 m = split($0, aline) @end example At this point, we should be curious to see what our records were split @@ -28803,10 +28947,10 @@ into, so we try to look: @example gawk> @kbd{p n m alast aline} -@print{} n = number (5) -@print{} m = number (5) +@print{} n = 5 +@print{} m = untyped variable @print{} alast = array, 5 elements -@print{} aline = array, 5 elements +@print{} aline = untyped variable @end example @noindent @@ -28814,7 +28958,9 @@ gawk> @kbd{p n m alast aline} @command{awk}'s @code{print} statement.) This is kind of disappointing, though. All we found out is that there -are five elements in each of our arrays. Useful enough (we now know that +are five elements in @code{alast}; @code{m} and @code{aline} don't have +values yet since we are at line 68 but haven't executed it yet. +This information is useful enough (we now know that none of the words were accidentally left out), but what if we want to see inside the array? @@ -28830,7 +28976,7 @@ Oops! @example gawk> @kbd{p alast[1]} -@print{} alast["1"] = string ("awk") +@print{} alast["1"] = "awk" @end example This would be kind of slow for a 100-member array, though, so @@ -28839,11 +28985,11 @@ not to be mentioned): @example gawk> @kbd{p @@alast} -@print{} alast["1"] = string ("awk") -@print{} alast["2"] = string ("is") -@print{} alast["3"] = string ("a") -@print{} alast["4"] = string ("wonderful") -@print{} alast["5"] = string ("program!") +@print{} alast["1"] = "awk" +@print{} alast["2"] = "is" +@print{} alast["3"] = "a" +@print{} alast["4"] = "wonderful" +@print{} alast["5"] = "program!" @end example It looks like we got this far OK. Let's take another step @@ -28851,9 +28997,9 @@ or two: @example gawk> @kbd{n} -@print{} 70 clast = join(alast, fcount, n) +@print{} 69 clast = join(alast, fcount, n) gawk> @kbd{n} -@print{} 71 cline = join(aline, fcount, m) +@print{} 70 cline = join(aline, fcount, m) @end example Well, here we are at our error (sorry to spoil the suspense). What we @@ -28863,8 +29009,8 @@ this would work. Let's look at what we've got: @example gawk> @kbd{p cline clast} -@print{} cline = string ("gawk is a wonderful program!") -@print{} clast = string ("awk is a wonderful program!") +@print{} cline = "gawk is a wonderful program!" +@print{} clast = "awk is a wonderful program!" @end example Hey, those look pretty familiar! They're just our original, unaltered, @@ -29711,7 +29857,9 @@ responds @samp{syntax error}. When you do figure out what your mistake was, though, you'll feel like a real guru. @item -If you perused the dump of opcodes in @ref{Miscellaneous Debugger Commands}, +@c NOTE: no comma after the ref{} on purpose, due to following +@c parenthetical remark. +If you perused the dump of opcodes in @ref{Miscellaneous Debugger Commands} (or if you are already familiar with @command{gawk} internals), you will realize that much of the internal manipulation of data in @command{gawk}, as in many interpreters, is done on a stack. @@ -29759,7 +29907,7 @@ similarly to the GNU Debugger, GDB. @item Debuggers let you step through your program one statement at a time, examine and change variable and array values, and do a number of other -things that let understand what your program is actually doing (as +things that let you understand what your program is actually doing (as opposed to what it is supposed to do). @item @@ -29797,6 +29945,12 @@ arbitrary precision integers, and concludes with a description of some points where @command{gawk} and the POSIX standard are not quite in agreement. +@quotation NOTE +Most users of @command{gawk} can safely skip this chapter. +But if you want to do scientific calculations with @command{gawk}, +this is the place to be. +@end quotation + @menu * Computer Arithmetic:: A quick intro to computer math. * Math Definitions:: Defining terms used. @@ -29916,8 +30070,23 @@ A special value representing infinity. Operations involving another number and infinity produce infinity. @item NaN -``Not A Number.'' A special value indicating a result that can't -happen in real math, but that can happen in floating-point computations. +``Not A Number.''@footnote{Thanks +to Michael Brennan for this description, which I have paraphrased, and +for the examples}. +A special value that results from attempting a +calculation that has no answer as a real number. In such a case, +programs can either receive a floating-point exception, or get @code{NaN} +back as the result. The IEEE 754 standard recommends that systems return +@code{NaN}. Some examples: + +@table @code +@item sqrt(-1) +This makes sense in the range of complex numbers, but not in the +range of real numbers, so the result is @code{NaN}. + +@item log(-8) +@minus{}8 is out of the domain of @code{log()}, so the result is @code{NaN}. +@end table @item Normalized How the significand (see later in this list) is usually stored. The @@ -30024,8 +30193,8 @@ array to provide information about the MPFR and GMP libraries The MPFR library provides precise control over precisions and rounding modes, and gives correctly rounded, reproducible, platform-independent -results. With either of the command-line options @option{--bignum} or -@option{-M}, all floating-point arithmetic operators and numeric functions +results. With the @option{-M} command-line option, +all floating-point arithmetic operators and numeric functions can yield results to any desired precision level supported by MPFR. Two built-in variables, @code{PREC} and @code{ROUNDMODE}, @@ -30039,7 +30208,7 @@ to follow. @quotation Math class is tough! -@author Late 1980's Barbie +@author Teen Talk Barbie, July 1992 @end quotation This @value{SECTION} provides a high level overview of the issues @@ -30335,7 +30504,7 @@ internally as a MPFR number. Changing the precision using @code{PREC} in the program text does @emph{not} change the precision of a constant. If you need to represent a floating-point constant at a higher precision -than the default and cannot use a command line assignment to @code{PREC}, +than the default and cannot use a command-line assignment to @code{PREC}, you should either specify the constant as a string, or as a rational number, whenever possible. The following example illustrates the differences among various ways to print a floating-point constant: @@ -30451,7 +30620,7 @@ output when you change the rounding mode to be sure. @cindex integers, arbitrary precision @cindex arbitrary precision integers -When given one of the options @option{--bignum} or @option{-M}, +When given the @option{-M} option, @command{gawk} performs all integer arithmetic using GMP arbitrary precision integers. Any number that looks like an integer in a source or @value{DF} is stored as an arbitrary precision integer. The size @@ -30704,7 +30873,7 @@ values. The default for @command{awk} is to use double-precision floating-point values. @item -In the 1980's, Barbie mistakenly said ``Math class is tough!'' +In the early 1990's, Barbie mistakenly said ``Math class is tough!'' While math isn't tough, floating-point arithmetic isn't the same as pencil and paper math, and care must be taken: @@ -30732,12 +30901,12 @@ Often, increasing the accuracy and then rounding to the desired number of digits produces reasonable results. @item -Use either @option{-M} or @option{--bignum} to enable MPFR +Use @option{-M} (or @option{--bignum}) to enable MPFR arithmetic. Use @code{PREC} to set the precision in bits, and @code{ROUNDMODE} to set the IEEE 754 rounding mode. @item -With @option{-M} or @option{--bignum}, @command{gawk} performs +With @option{-M}, @command{gawk} performs arbitrary precision integer arithmetic using the GMP library. This is faster and more space efficient than using MPFR for the same calculations. @@ -30969,7 +31138,7 @@ Some other bits and pieces: @itemize @value{BULLET} @item The API provides access to @command{gawk}'s @code{do_@var{xxx}} values, -reflecting command line options, like @code{do_lint}, @code{do_profiling} +reflecting command-line options, like @code{do_lint}, @code{do_profiling} and so on (@pxref{Extension API Variables}). These are informational: an extension cannot affect their values inside @command{gawk}. In addition, attempting to assign to them @@ -31120,7 +31289,7 @@ does not support this keyword, you should either place @file{config.h} file in your extensions. @item -All pointers filled in by @command{gawk} are to memory +All pointers filled in by @command{gawk} point to memory managed by @command{gawk} and should be treated by the extension as read-only. Memory for @emph{all} strings passed into @command{gawk} from the extension @emph{must} come from calling the API-provided function @@ -31654,8 +31823,8 @@ empty string (@code{""}). The @code{func} pointer is the address of a An @dfn{exit callback} function is a function that @command{gawk} calls before it exits. Such functions are useful if you have general ``cleanup'' tasks -that should be performed in your extension (such as closing data -base connections or other resource deallocations). +that should be performed in your extension (such as closing database +connections or other resource deallocations). You can register such a function with @command{gawk} using the following function. @@ -34733,6 +34902,7 @@ should be the place to do so. @end itemize +@c EXCLUDE START @node Extension Exercises @section Exercises @@ -34755,6 +34925,7 @@ Write a wrapper script that provides an interface similar to @ref{Extension Sample Inplace}. @end enumerate +@c EXCLUDE END @ifnotinfo @part @value{PART4}Appendices @@ -35185,7 +35356,7 @@ Indirect function calls @item Directories on the command line produce a warning and are skipped -(@pxref{Command line directories}). +(@pxref{Command-line directories}). @end itemize @item @@ -35269,8 +35440,7 @@ functions for internationalization (@pxref{Programmer i18n}). @item -The @code{fflush()} function from Brian Kernighan's -version of @command{awk} +The @code{fflush()} function from BWK @command{awk} (@pxref{I/O Functions}). @item @@ -35334,7 +35504,7 @@ and the @option{--copyright}, @option{--debug}, @option{--dump-variables}, -@option{--execle}, +@option{--exec}, @option{--field-separator}, @option{--file}, @option{--gen-pot}, @@ -35415,6 +35585,10 @@ and the documentation for @command{gawk} @value{PVERSION} 4.1: Ultrix @end itemize +@item +@c FIXME: Verify the version here. +Support for MirBSD was removed at @command{gawk} @value{PVERSION} 4.2. + @end itemize @c XXX ADD MORE STUFF HERE @@ -35532,7 +35706,7 @@ The ability to delete all of an array at once with @samp{delete @var{array}} (@pxref{Delete}). @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -35590,12 +35764,12 @@ The @code{next file} statement became @code{nextfile} @item The @code{fflush()} function from -Brian Kernighan's @command{awk} +BWK @command{awk} (then at Bell Laboratories; @pxref{I/O Functions}). @item -New command line options: +New command-line options: @itemize @value{MINUS} @item @@ -35605,7 +35779,7 @@ the original Version 7 Unix version of @command{awk} (@pxref{V7/SVR3.1}). @item -The @option{-m} option from Brian Kernighan's @command{awk}. (He was +The @option{-m} option from BWK @command{awk}. (Brian was still at Bell Laboratories at the time.) This was later removed from both his @command{awk} and from @command{gawk}. @@ -35847,7 +36021,7 @@ An optional third argument to (@pxref{String Functions}). @item -The behavior of @code{fflush()} changed to match Brian Kernighan's @command{awk} +The behavior of @code{fflush()} changed to match BWK @command{awk} and for POSIX; now both @samp{fflush()} and @samp{fflush("")} flush all open output redirections (@pxref{I/O Functions}). @@ -35885,7 +36059,7 @@ Indirect function calls (@pxref{Switch Statement}). @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -35910,7 +36084,7 @@ All long options acquired corresponding short options, for use in @samp{#!} scri @item Directories named on the command line now produce a warning, not a fatal error, unless @option{--posix} or @option{--traditional} are used -(@pxref{Command line directories}). +(@pxref{Command-line directories}). @item The @command{gawk} internals were rewritten, bringing the @command{dgawk} @@ -35986,10 +36160,10 @@ Three new arrays: @item The three executables @command{gawk}, @command{pgawk}, and @command{dgawk}, were merged into -one, named just @command{gawk}. As a result the command line options changed. +one, named just @command{gawk}. As a result the command-line options changed. @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -37331,7 +37505,7 @@ The following changes the record separator to @code{"\r\n"} and sets binary mode on reads, but does not affect the mode on standard input: @example -gawk -v RS="\r\n" --source "BEGIN @{ BINMODE = 1 @}" @dots{} +gawk -v RS="\r\n" -e "BEGIN @{ BINMODE = 1 @}" @dots{} @end example @noindent @@ -37944,7 +38118,7 @@ since approximately 2003. @cindex source code, @command{pawk} @item @command{pawk} Nelson H.F.@: Beebe at the University of Utah has modified -Brian Kernighan's @command{awk} to provide timing and profiling information. +BWK @command{awk} to provide timing and profiling information. It is different from @command{gawk} with the @option{--profile} option. (@pxref{Profiling}), in that it uses CPU-based profiling, not line-count @@ -38007,8 +38181,7 @@ This is an embeddable @command{awk} interpreter derived from This is a Python module that claims to bring @command{awk}-like features to Python. See @uref{https://github.com/alecthomas/pawk} for more information. (This is not related to Nelson Beebe's -modified version of Brian Kernighan's @command{awk}, -described earlier.) +modified version of BWK @command{awk}, described earlier.) @item @w{QSE Awk} @cindex QSE Awk @@ -38147,7 +38320,7 @@ as well as any considerations you should bear in mind. @appendixsubsec Accessing The @command{gawk} Git Repository As @command{gawk} is Free Software, the source code is always available. -@ref{Gawk Distribution}, describes how to get and build the formal, +@DBREF{Gawk Distribution} describes how to get and build the formal, released versions of @command{gawk}. @cindex @command{git} utility @@ -39029,7 +39202,7 @@ compiled with @samp{-DDEBUG}. @item The source code for @command{gawk} is maintained in a publicly -accessable Git repository. Anyone may check it out and view the source. +accessible Git repository. Anyone may check it out and view the source. @item Contributions to @command{gawk} are welcome. Following the steps @@ -41367,13 +41540,14 @@ Consistency issues: Use "zeros" instead of "zeroes". Use "nonzero" not "non-zero". Use "runtime" not "run time" or "run-time". - Use "command-line" not "command line". + Use "command-line" as an adjective and "command line" as a noun. Use "online" not "on-line". Use "whitespace" not "white space". Use "Input/Output", not "input/output". Also "I/O", not "i/o". Use "lefthand"/"righthand", not "left-hand"/"right-hand". Use "workaround", not "work-around". Use "startup"/"cleanup", not "start-up"/"clean-up" + Use "filesystem", not "file system" Use @code{do}, and not @code{do}-@code{while}, except where actually discussing the do-while. Use "versus" in text and "vs." in index entries @@ -41388,8 +41562,6 @@ Consistency issues: The numbers zero through ten should be spelled out, except when talking about file descriptor numbers. > 10 and < 0, it's ok to use numbers. - In tables, put command-line options in @code, while in the text, - put them in @option. For most cases, do NOT put a comma before "and", "or" or "but". But exercise taste with this rule. Don't show the awk command with a program in quotes when it's diff --git a/doc/gawktexi.in b/doc/gawktexi.in index bca15569..679073bf 100644 --- a/doc/gawktexi.in +++ b/doc/gawktexi.in @@ -46,7 +46,7 @@ @c applies to and all the info about who's publishing this edition @c These apply across the board. -@set UPDATE-MONTH July, 2014 +@set UPDATE-MONTH August, 2014 @set VERSION 4.1 @set PATCHLEVEL 1 @@ -160,6 +160,19 @@ @end macro @end ifdocbook +@c hack for docbook, where comma shouldn't always follow an @ref{} +@ifdocbook +@macro DBREF{text} +@ref{\text\} +@end macro +@end ifdocbook + +@ifnotdocbook +@macro DBREF{text} +@ref{\text\}, +@end macro +@end ifnotdocbook + @ifclear FOR_PRINT @set FN file name @set FFN File Name @@ -521,10 +534,10 @@ particular records in a file and perform operations upon them. * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between @samp{[...]}. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. * Records:: Controlling how data is split into records. @@ -541,7 +554,7 @@ particular records in a file and perform operations upon them. * Single Character Fields:: Making each character a separate field. * Command Line Field Separator:: Setting @code{FS} from the - command-line. + command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @@ -567,7 +580,7 @@ particular records in a file and perform operations upon them. @code{getline}. * Getline Summary:: Summary of @code{getline} Variants. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -595,7 +608,7 @@ particular records in a file and perform operations upon them. * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. * Values:: Constants, Variables, and Regular Expressions. * Constants:: String, numeric and regexp constants. @@ -606,7 +619,7 @@ particular records in a file and perform operations upon them. * Variables:: Variables give names to values for later use. * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. * Conversion:: The conversion of strings to numbers @@ -782,7 +795,7 @@ particular records in a file and perform operations upon them. information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. * Running Examples:: How to run these examples. * Clones:: Clones of common utilities. * Cut Program:: The @command{cut} utility. @@ -1206,23 +1219,18 @@ March, 2001 </prefaceinfo> @end docbook -Several kinds of tasks occur repeatedly -when working with text files. -You might want to extract certain lines and discard the rest. -Or you may need to make changes wherever certain patterns appear, -but leave the rest of the file alone. -Writing single-use programs for these tasks in languages such as C, C++, -or Java is time-consuming and inconvenient. -Such jobs are often easier with @command{awk}. -The @command{awk} utility interprets a special-purpose programming language -that makes it easy to handle simple data-reformatting jobs. +Several kinds of tasks occur repeatedly when working with text files. +You might want to extract certain lines and discard the rest. Or you +may need to make changes wherever certain patterns appear, but leave the +rest of the file alone. Such jobs are often easy with @command{awk}. +The @command{awk} utility interprets a special-purpose programming +language that makes it easy to handle simple data-reformatting jobs. -@cindex Brian Kernighan's @command{awk} The GNU implementation of @command{awk} is called @command{gawk}; if you invoke it with the proper options or environment variables (@pxref{Options}), it is fully compatible with -the POSIX@footnote{The 2008 POSIX standard is accessable online at +the POSIX@footnote{The 2008 POSIX standard is accessible online at @w{@url{http://www.opengroup.org/onlinepubs/9699919799/}.}} specification of the @command{awk} language and with the Unix version of @command{awk} maintained @@ -1296,7 +1304,7 @@ different computing environments. This @value{DOCUMENT}, while describing the @command{awk} language in general, also describes the particular implementation of @command{awk} called @command{gawk} (which stands for ``GNU @command{awk}''). @command{gawk} runs on a broad range of Unix systems, -ranging from Intel@registeredsymbol{}-architecture PC-based computers +ranging from Intel-architecture PC-based computers up through large-scale systems. @command{gawk} has also been ported to Mac OS X, Microsoft Windows @@ -1371,7 +1379,7 @@ help from me, thoroughly reworked @command{gawk} for compatibility with the newer @command{awk}. Circa 1994, I became the primary maintainer. Current development focuses on bug fixes, -performance improvements, standards compliance, and occasionally, new features. +performance improvements, standards compliance and, occasionally, new features. In May of 1997, J@"urgen Kahrs felt the need for network access from @command{awk}, and with a little help from me, set about adding @@ -1396,29 +1404,27 @@ for a complete list of those who made important contributions to @command{gawk}. The @command{awk} language has evolved over the years. Full details are provided in @ref{Language History}. The language described in this @value{DOCUMENT} -is often referred to as ``new @command{awk}'' (@command{nawk}). +is often referred to as ``new @command{awk}''. +By analogy, the original version of @command{awk} is +referred to as ``old @command{awk}.'' -@cindex @command{awk}, versions of -@cindex @command{nawk} utility -@cindex @command{oawk} utility -For some time after new @command{awk} was introduced, there were -systems with multiple versions of @command{awk}. Some systems had -an @command{awk} utility that implemented the original version of the -@command{awk} language and a @command{nawk} utility for the new version. -Others had an @command{oawk} version for the ``old @command{awk}'' -language and plain @command{awk} for the new one. Still others only -had one version, which is usually the new one. - -Today, only Solaris systems still use an old @command{awk} for the -default @command{awk} utility. (A more modern @command{awk} lives in -@file{/usr/xpg6/bin} on these systems.) All other modern systems use -some version of new @command{awk}.@footnote{Many of these systems use -@command{gawk} for their @command{awk} implementation!} - -It is likely that you already have some version of new @command{awk} on -your system, which is what you should use when running your programs. -(Of course, if you're reading this @value{DOCUMENT}, chances are good -that you have @command{gawk}!) +Today, on most systems, when you run the @command{awk} utility, +you get some version of new @command{awk}.@footnote{Only +Solaris systems still use an old @command{awk} for the +default @command{awk} utility. A more modern @command{awk} lives in +@file{/usr/xpg6/bin} on these systems.} If your system's standard +@command{awk} is the old one, you will see something like this +if you try the test program: + +@example +$ @kbd{awk 1 /dev/null} +@error{} awk: syntax error near line 1 +@error{} awk: bailing out near line 1 +@end example + +@noindent +In this case, you should find a version of new @command{awk}, +or just install @command{gawk}! Throughout this @value{DOCUMENT}, whenever we refer to a language feature that should be available in any complete implementation of POSIX @command{awk}, @@ -1469,7 +1475,9 @@ There are sidebars scattered throughout the @value{DOCUMENT}. They add a more complete explanation of points that are relevant, but not likely to be of interest on first reading. +@ifclear FOR_PRINT All appear in the index, under the heading ``sidebar.'' +@end ifclear Most of the time, the examples use complete @command{awk} programs. Some of the more advanced sections show only the part of the @command{awk} @@ -1624,6 +1632,9 @@ try looking them up here. @uref{http://www.gnu.org/software/gawk/manual/html_node/GNU-Free-Documentation-License.html, The GNU FDL} is the license that covers this @value{DOCUMENT}. + +Some of the chapters have exercise sections; these have also been +omitted from the print edition. @end ifset @ifclear FOR_PRINT @@ -1664,11 +1675,18 @@ are slightly different than in other books you may have read. This @value{SECTION} briefly documents the typographical conventions used in Texinfo. @end ifinfo -Examples you would type at the command-line are preceded by the common +Examples you would type at the command line are preceded by the common shell primary and secondary prompts, @samp{$} and @samp{>}. Input that you type is shown @kbd{like this}. +@c 8/2014: @print{} is stripped from the texi to make docbook. +@ifclear FOR_PRINT Output from the command is preceded by the glyph ``@print{}''. This typically represents the command's standard output. +@end ifclear +@ifset FOR_PRINT +Output from the command, usually its standard output, appears +@code{like this}. +@end ifset Error messages, and other output on the command's standard error, are preceded by the glyph ``@error{}''. For example: @@ -1698,6 +1716,10 @@ another key, at the same time. For example, a @kbd{Ctrl-d} is typed by first pressing and holding the @kbd{CONTROL} key, next pressing the @kbd{d} key and finally releasing both keys. +For the sake of brevity, throughout this @value{DOCUMENT}, we refer to +Brian Kernighan's version of @command{awk} as ``BWK @command{awk}.'' +(@xref{Other Versions}, for information on his and other versions.) + @ifset FOR_PRINT @quotation NOTE Notes of interest look like this. @@ -1737,6 +1759,7 @@ They also appear in the index under the heading ``dark corner.'' As noted by the opening quote, though, any coverage of dark corners is, by definition, incomplete. +@cindex c.e., See common extensions Extensions to the standard @command{awk} language that are supported by more than one @command{awk} implementation are marked @ifclear FOR_PRINT @@ -1744,7 +1767,7 @@ more than one @command{awk} implementation are marked and ``extensions, common.'' @end ifclear @ifset FOR_PRINT -``@value{COMMONEXT}.'' +``@value{COMMONEXT}'' for ``common extension.'' @end ifset @node Manual History @@ -1783,6 +1806,7 @@ see @uref{http://www.gnu.org, the GNU Project's home page}. This @value{DOCUMENT} may also be read from @uref{http://www.gnu.org/software/gawk/manual/, their web site}. +@ifclear FOR_PRINT A shell, an editor (Emacs), highly portable optimizing C, C++, and Objective-C compilers, a symbolic debugger and dozens of large and small utilities (such as @command{gawk}), have all been completed and are @@ -1793,32 +1817,16 @@ stage of development. @cindex Linux @cindex GNU/Linux @cindex operating systems, BSD-based -@cindex Alpha (DEC) Until the GNU operating system is more fully developed, you should consider using GNU/Linux, a freely distributable, Unix-like operating -system for Intel@registeredsymbol{}, +system for Intel, Power Architecture, Sun SPARC, IBM S/390, and other -@ifclear FOR_PRINT systems.@footnote{The terminology ``GNU/Linux'' is explained in the @ref{Glossary}.} -@end ifclear -@ifset FOR_PRINT -systems. -@end ifset Many GNU/Linux distributions are available for download from the Internet. - -(There are numerous other freely available, Unix-like operating systems -based on the -Berkeley Software Distribution, and some of them use recent versions -of @command{gawk} for their versions of @command{awk}. -@uref{http://www.netbsd.org, NetBSD}, -@uref{http://www.freebsd.org, FreeBSD}, -and -@uref{http://www.openbsd.org, OpenBSD} -are three of the most popular ones, but there -are others.) +@end ifclear @ifnotinfo The @value{DOCUMENT} you are reading is actually free---at least, the @@ -2062,17 +2070,29 @@ people. Notable code and documentation contributions were made by a number of people. @xref{Contributors}, for the full list. -Thanks to Patrice Dumas for the new @command{makeinfo} program. +Thanks to Patrice Dumas for the new @command{makeinfo} program. Thanks to Karl Berry who continues to work to keep the Texinfo markup language sane. @cindex Kernighan, Brian +@cindex Brennan, Michael +@cindex Day, Robert P.J.@: +Robert P.J.@: Day, Michael Brennan and Brian Kernighan kindly acted as +reviewers for the 2015 edition of this @value{DOCUMENT}. Their feedback +helped improve the final work. + I would like to thank Brian Kernighan for invaluable assistance during the testing and debugging of @command{gawk}, and for ongoing help and advice in clarifying numerous points about the language. We could not have done nearly as good a job on either @command{gawk} or its documentation without his help. +Brian is in a class by himself as a programmer and technical +author. I have to thank him (yet again) for his ongoing friendship +and the role model he has been for me for close to 30 years! +Having him as a reviewer is an exciting privilege. It has also +been extremely humbling@enddots{} + @cindex Robbins, Miriam @cindex Robbins, Jean @cindex Robbins, Harry @@ -2307,29 +2327,27 @@ For example, on OS/2, it is @kbd{Ctrl-z}.) As an example, the following program prints a friendly piece of advice (from Douglas Adams's @cite{The Hitchhiker's Guide to the Galaxy}), to keep you from worrying about the complexities of computer -programming@footnote{If you use Bash as your shell, you should execute -the command @samp{set +H} before running this program interactively, -to disable the C shell-style command history, which treats -@samp{!} as a special character. We recommend putting this command into -your personal startup file.} -(@code{BEGIN} is a feature we haven't discussed yet): +programming: @example -$ @kbd{awk "BEGIN @{ print \"Don't Panic!\" @}"} +$ @kbd{awk "BEGIN @{ print "Don\47t Panic!" @}"} @print{} Don't Panic! @end example -@cindex shell quoting, double quote -@cindex double quote (@code{"}) in shell commands -@cindex @code{"} (double quote) in shell commands -@cindex @code{\} (backslash) in shell commands -@cindex backslash (@code{\}) in shell commands -This program does not read any input. The @samp{\} before each of the -inner double quotes is necessary because of the shell's quoting -rules---in particular because it mixes both single quotes and -double quotes.@footnote{Although we generally recommend the use of single -quotes around the program text, double quotes are needed here in order to -put the single quote into the message.} +@command{awk} executes statements associated with @code{BEGIN} before +reading any input. If there are no other statements in your program, +as is the case here, @command{awk} just stops, instead of trying to read +input it doesn't know how to process. +The @samp{\47} is a magic way of getting a single quote into +the program, without having to engage in ugly shell quoting tricks. + +@quotation NOTE +As a side note, if you use Bash as your shell, you should execute the +command @samp{set +H} before running this program interactively, to +disable the C shell-style command history, which treats @samp{!} as a +special character. We recommend putting this command into your personal +startup file. +@end quotation This next simple @command{awk} program emulates the @command{cat} utility; it copies whatever you type on the @@ -2364,9 +2382,10 @@ awk -f @var{source-file} @var{input-file1} @var{input-file2} @dots{} @cindex @option{-f} option @cindex command line, option @option{-f} -The @option{-f} instructs the @command{awk} utility to get the @command{awk} program -from the file @var{source-file}. Any @value{FN} can be used for -@var{source-file}. For example, you could put the program: +The @option{-f} instructs the @command{awk} utility to get the +@command{awk} program from the file @var{source-file} (@pxref{Options}). +Any @value{FN} can be used for @var{source-file}. For example, you +could put the program: @example BEGIN @{ print "Don't Panic!" @} @@ -2427,16 +2446,7 @@ BEGIN @{ print "Don't Panic!" @} @noindent After making this file executable (with the @command{chmod} utility), simply type @samp{advice} -at the shell and the system arranges to run @command{awk}@footnote{The -line beginning with @samp{#!} lists the full @value{FN} of an interpreter -to run and an optional initial command-line argument to pass to that -interpreter. The operating system then runs the interpreter with the given -argument and the full argument list of the executed program. The first argument -in the list is the full @value{FN} of the @command{awk} program. -The rest of the -argument list contains either options to @command{awk}, or @value{DF}s, -or both. Note that on many systems @command{awk} may be found in -@file{/usr/bin} instead of in @file{/bin}. Caveat Emptor.} as if you had +at the shell and the system arranges to run @command{awk} as if you had typed @samp{awk -f advice}: @example @@ -2454,9 +2464,27 @@ Self-contained @command{awk} scripts are useful when you want to write a program that users can invoke without their having to know that the program is written in @command{awk}. -@sidebar Portability Issues with @samp{#!} +@sidebar Understanding @samp{#!} @cindex portability, @code{#!} (executable scripts) +@command{awk} is an @dfn{interpreted} language. This means that the +@command{awk} utility reads your program and then processes your data +according to the instructions in your program. (This is different +from a @dfn{compiled} language such as C, where your program is first +compiled into machine code that is executed directly by your system's +hardware.) The @command{awk} utility is thus termed an @dfn{interpreter}. +Many modern languages are interperted. + +The line beginning with @samp{#!} lists the full @value{FN} of an +interpreter to run and a single optional initial command-line argument +to pass to that interpreter. The operating system then runs the +interpreter with the given argument and the full argument list of the +executed program. The first argument in the list is the full @value{FN} +of the @command{awk} program. The rest of the argument list contains +either options to @command{awk}, or @value{DF}s, or both. Note that on +many systems @command{awk} may be found in @file{/usr/bin} instead of +in @file{/bin}. Caveat Emptor. + Some systems limit the length of the interpreter name to 32 characters. Often, this can be dealt with by using a symbolic link. @@ -2468,8 +2496,7 @@ of some sort from @command{awk}. @cindex @code{ARGC}/@code{ARGV} variables, portability and @cindex portability, @code{ARGV} variable -Finally, -the value of @code{ARGV[0]} +Finally, the value of @code{ARGV[0]} (@pxref{Built-in Variables}) varies depending upon your operating system. Some systems put @samp{awk} there, some put the full pathname @@ -2648,7 +2675,7 @@ Note that the single quote is not special within double quotes. @item Null strings are removed when they occur as part of a non-null -command-line argument, while explicit non-null objects are kept. +command-line argument, while explicit null objects are kept. For example, to specify that the field separator @code{FS} should be set to the null string, use: @@ -2795,7 +2822,9 @@ each line is considered to be one @dfn{record}. In the @value{DF} @file{mail-list}, each record contains the name of a person, his/her phone number, his/her email-address, and a code for their relationship -with the author of the list. An @samp{A} in the last column +with the author of the list. +The columns are aligned using spaces. +An @samp{A} in the last column means that the person is an acquaintance. An @samp{F} in the last column means that the person is a friend. An @samp{R} means that the person is a relative: @@ -2829,6 +2858,7 @@ of green crates shipped, the number of red boxes shipped, the number of orange bags shipped, and the number of blue packages shipped, respectively. There are 16 entries, covering the 12 months of last year and the first four months of the current year. +An empty line separates the data for the two years. @example @c file eg/data/inventory-shipped @@ -2924,34 +2954,39 @@ you can come up with different ways to do the same things shown here: @itemize @value{BULLET} @item -Print the length of the longest input line: +Print every line that is longer than 80 characters: @example -awk '@{ if (length($0) > max) max = length($0) @} - END @{ print max @}' data +awk 'length($0) > 80' data @end example +The sole rule has a relational expression as its pattern and it has no +action---so it uses the default action, printing the record. + @item -Print every line that is longer than 80 characters: +Print the length of the longest input line: @example -awk 'length($0) > 80' data +awk '@{ if (length($0) > max) max = length($0) @} + END @{ print max @}' data @end example -The sole rule has a relational expression as its pattern and it has no -action---so it uses the default action, printing the record. +The code associated with @code{END} executes after all +input has been read; it's the other side of the coin to @code{BEGIN}. @cindex @command{expand} utility @item Print the length of the longest line in @file{data}: @example -expand data | awk '@{ if (x < length()) x = length() @} +expand data | awk '@{ if (x < length($0)) x = length($0) @} END @{ print "maximum line length is " x @}' @end example +This example differs slightly from the previous one: The input is processed by the @command{expand} utility to change TABs -into spaces, so the widths compared are actually the right-margin columns. +into spaces, so the widths compared are actually the right-margin columns, +as opposed to the number of input characters on each line. @item Print every line that has at least one field: @@ -3078,8 +3113,8 @@ features that haven't been covered yet, so don't worry if you don't understand all the details: @example -LC_ALL=C ls -l | awk '$6 == "Nov" @{ sum += $5 @} - END @{ print sum @}' +ls -l | awk '$6 == "Nov" @{ sum += $5 @} + END @{ print sum @}' @end example @cindex @command{ls} utility @@ -3297,7 +3332,7 @@ and array sorting. As we develop our presentation of the @command{awk} language, we introduce most of the variables and many of the functions. They are described -systematically in @ref{Built-in Variables}, and +systematically in @ref{Built-in Variables}, and in @ref{Built-in}. @node When @@ -3332,33 +3367,30 @@ eight-bit microprocessors, and a microcode assembler for a special-purpose Prolog computer. While the original @command{awk}'s capabilities were strained by tasks -of such complexity, modern versions are more capable. Even Brian Kernighan's -version of @command{awk} has fewer predefined limits, and those -that it has are much larger than they used to be. +of such complexity, modern versions are more capable. @cindex @command{awk} programs, complex -If you find yourself writing @command{awk} scripts of more than, say, a few -hundred lines, you might consider using a different programming -language. -The shell is good at string and -pattern matching; in addition, it allows powerful use of the system -utilities. More conventional languages, such as C, C++, and Java, offer -better facilities for system programming and for managing the complexity -of large programs. -Python offers a nice balance between high-level ease of programming and -access to system facilities. -Programs in these languages may require more lines -of source code than the equivalent @command{awk} programs, but they are -easier to maintain and usually run more efficiently. +If you find yourself writing @command{awk} scripts of more than, say, +a few hundred lines, you might consider using a different programming +language. The shell is good at string and pattern matching; in addition, +it allows powerful use of the system utilities. Python offers a nice +balance between high-level ease of programming and access to system +facilities.@footnote{Other popular scripting languages include Ruby +and Perl.} @node Intro Summary @section Summary +@c FIXME: Review this chapter for summary of builtin functions called. @itemize @value{BULLET} @item Programs in @command{awk} consist of @var{pattern}-@var{action} pairs. @item +An @var{action} without a @var{pattern} always runs. The default +@var{action} for a pattern without one is @samp{@{ print $0 @}}. + +@item Use either @samp{awk '@var{program}' @var{files}} or @@ -3580,7 +3612,7 @@ multibyte characters. This option is an easy way to tell @command{gawk}: @cindex compatibility mode (@command{gawk}), specifying Specify @dfn{compatibility mode}, in which the GNU extensions to the @command{awk} language are disabled, so that @command{gawk} behaves just -like Brian Kernighan's version @command{awk}. +like BWK @command{awk}. @xref{POSIX/GNU}, which summarizes the extensions. @ifclear FOR_PRINT @@ -3665,7 +3697,7 @@ Command-line variable assignments of the form This option is particularly necessary for World Wide Web CGI applications that pass arguments through the URL; using this option prevents a malicious (or other) user from passing in options, assignments, or @command{awk} source -code (via @option{--source}) to the CGI application. This option should be used +code (via @option{-e}) to the CGI application. This option should be used with @samp{#!} scripts (@pxref{Executable Scripts}), like so: @example @@ -3711,7 +3743,7 @@ Second, because this option is intended to be used with code libraries, @command{gawk} does not recognize such files as constituting main program 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. +or on the command line. @item @option{-l} @var{ext} @itemx @option{--load} @var{ext} @@ -3735,7 +3767,7 @@ a shared library. This feature is described in detail in @ref{Dynamic Extension @cindex warnings, issuing Warn about constructs that are dubious or nonportable to other @command{awk} implementations. -No space is allowed between the @option{-D} and @var{value}, if +No space is allowed between the @option{-L} and @var{value}, if @var{value} is supplied. Some warnings are issued when @command{gawk} first reads your program. Others are issued at runtime, as your program executes. @@ -3854,7 +3886,7 @@ Newlines are not allowed after @samp{?} or @samp{:} @cindex @code{FS} variable, as TAB character @item -Specifying @samp{-Ft} on the command-line does not set the value +Specifying @samp{-Ft} on the command line does not set the value of @code{FS} to be a single TAB character (@pxref{Field Separators}). @@ -3951,14 +3983,14 @@ source of data.) Because it is clumsy using the standard @command{awk} mechanisms to mix source file and command-line @command{awk} programs, @command{gawk} -provides the @option{--source} option. This does not require you to +provides the @option{-e} option. This does not require you to pre-empt the standard input for your source code; it allows you to easily mix command-line and library source code (@pxref{AWKPATH Variable}). -As with @option{-f}, the @option{--source} and @option{--include} +As with @option{-f}, the @option{-e} and @option{-i} options may also be used multiple times on the command line. -@cindex @option{--source} option -If no @option{-f} or @option{--source} option is specified, then @command{gawk} +@cindex @option{-e} option +If no @option{-f} or @option{-e} option is specified, then @command{gawk} uses the first non-option command-line argument as the text of the program source code. @@ -4026,6 +4058,11 @@ included. As each element of @code{ARGV} is processed, @command{gawk} sets the variable @code{ARGIND} to the index in @code{ARGV} of the current element. +@c FIXME: One day, move the ARGC and ARGV node closer to here. +Changing @code{ARGC} and @code{ARGV} in your @command{awk} program lets +you control how @command{awk} processes the input files; this is described +in more detail in @ref{ARGC and ARGV}. + @cindex input files, variable assignments and @cindex variable assignments and input files The distinction between @value{FN} arguments and variable-assignment @@ -4100,7 +4137,7 @@ with @code{getline}. Some other versions of @command{awk} also support this, but it is not standard. (Some operating systems provide a @file{/dev/stdin} file -in the file system; however, @command{gawk} always processes +in the filesystem; however, @command{gawk} always processes this @value{FN} itself.) @node Environment Variables @@ -4126,7 +4163,7 @@ behaves. @cindex differences in @command{awk} and @command{gawk}, @code{AWKPATH} environment variable @ifinfo The previous @value{SECTION} described how @command{awk} program files can be named -on the command-line with the @option{-f} option. +on the command line with the @option{-f} option. @end ifinfo In most @command{awk} implementations, you must supply a precise path name for each program @@ -4154,7 +4191,7 @@ standard directory in the default path and then specified on the command line with a short @value{FN}. Otherwise, the full @value{FN} would have to be typed for each file. -By using the @option{-i} option, or the @option{--source} and @option{-f} options, your command-line +By using the @option{-i} option, or the @option{-e} and @option{-f} options, your command-line @command{awk} programs can use facilities in @command{awk} library files (@pxref{Library Functions}). Path searching is not done if @command{gawk} is in compatibility mode. @@ -4221,7 +4258,7 @@ list are meant to be used by regular users. @table @env @item POSIXLY_CORRECT -Causes @command{gawk} to switch POSIX compatibility +Causes @command{gawk} to switch to POSIX compatibility mode, disabling all traditional and GNU extensions. @xref{Options}. @@ -4254,7 +4291,7 @@ file as the size of the memory buffer to allocate for I/O. Otherwise, the value should be a number, and @command{gawk} uses that number as the size of the buffer to allocate. (When this variable is not set, @command{gawk} uses the smaller of the file's size and the ``default'' -blocksize, which is usually the file systems I/O blocksize.) +blocksize, which is usually the filesystems I/O blocksize.) @item AWK_HASH If this variable exists with a value of @samp{gst}, @command{gawk} @@ -4327,6 +4364,9 @@ to @code{EXIT_FAILURE}. This @value{SECTION} describes a feature that is specific to @command{gawk}. +@cindex @code{@@include} directive +@cindex file inclusion, @code{@@include} directive +@cindex including files, @code{@@include} directive The @code{@@include} keyword can be used to read external @command{awk} source files. This gives you the ability to split large @command{awk} source files into smaller, more manageable pieces, and also lets you reuse common @command{awk} @@ -4446,6 +4486,9 @@ and this also applies to files named with @code{@@include}. This @value{SECTION} describes a feature that is specific to @command{gawk}. +@cindex @code{@@load} directive +@cindex loading extensions, @code{@@load} directive +@cindex extensions, loading, @code{@@load} directive The @code{@@load} keyword can be used to read external @command{awk} extensions (stored as system shared libraries). This allows you to link in compiled code that may offer superior @@ -4587,9 +4630,9 @@ or to run @command{awk}. @item -The three standard @command{awk} options are @option{-f}, @option{-F} -and @option{-v}. @command{gawk} supplies these and many others, as well -as corresponding GNU-style long options. +The three standard options for all versions of @command{awk} are +@option{-f}, @option{-F} and @option{-v}. @command{gawk} supplies these +and many others, as well as corresponding GNU-style long options. @item Non-option command-line arguments are usually treated as @value{FN}s, @@ -4647,7 +4690,7 @@ The simplest regular expression is a sequence of letters, numbers, or both. Such a regexp matches any string that contains that sequence. Thus, the regexp @samp{foo} matches any string containing @samp{foo}. Therefore, the pattern @code{/foo/} matches any input record containing -the three characters @samp{foo} @emph{anywhere} in the record. Other +the three adjacent characters @samp{foo} @emph{anywhere} in the record. Other kinds of regexps let you specify more complicated classes of strings. @ifnotinfo @@ -4661,10 +4704,10 @@ regular expressions work, we present more complicated instances. * Escape Sequences:: How to write nonprinting characters. * Regexp Operators:: Regular Expression Operators. * Bracket Expressions:: What can go between @samp{[...]}. -* GNU Regexp Operators:: Operators specific to GNU software. -* Case-sensitivity:: How to do case-insensitive matching. * Leftmost Longest:: How much text matches. * Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. * Regexp Summary:: Regular expressions summary. @end menu @@ -4856,20 +4899,30 @@ between @samp{0} and @samp{7}. For example, the code for the ASCII ESC @item \x@var{hh}@dots{} The hexadecimal value @var{hh}, where @var{hh} stands for a sequence of hexadecimal digits (@samp{0}--@samp{9}, and either @samp{A}--@samp{F} -or @samp{a}--@samp{f}). Like the same construct -in ISO C, the escape sequence continues until the first nonhexadecimal -digit is seen. @value{COMMONEXT} +or @samp{a}--@samp{f}). A maximum of two digts are allowed after +the @samp{\x}. Any further hexadecimal digits are treated as simple +letters or numbers. @value{COMMONEXT} + +@quotation CAUTION +In ISO C, the escape sequence continues until the first nonhexadecimal +digit is seen. +@c FIXME: Add exact version here. +For many years, @command{gawk} would continue incorporating +hexadecimal digits into the value until a non-hexadecimal digit +or the end of the string was encountered. However, using more than two hexadecimal digits produces -undefined results. (The @samp{\x} escape sequence is not allowed in -POSIX @command{awk}.) +@end quotation @cindex @code{\} (backslash), @code{\/} escape sequence @cindex backslash (@code{\}), @code{\/} escape sequence @item \/ A literal slash (necessary for regexp constants only). This sequence is used when you want to write a regexp -constant that contains a slash. Because the regexp is delimited by -slashes, you need to escape the slash that is part of the pattern, +constant that contains a slash +(such as @code{/.*:\/home\/[[:alnum:]]+:.*/}; the @samp{[[:alnum:]]} +notation is discussed shortly, in @ref{Bracket Expressions}). +Because the regexp is delimited by +slashes, you need to escape any slash that is part of the pattern, in order to tell @command{awk} to keep processing the rest of the regexp. @cindex @code{\} (backslash), @code{\"} escape sequence @@ -4877,8 +4930,10 @@ in order to tell @command{awk} to keep processing the rest of the regexp. @item \" A literal double quote (necessary for string constants only). This sequence is used when you want to write a string -constant that contains a double quote. Because the string is delimited by -double quotes, you need to escape the quote that is part of the string, +constant that contains a double quote +(such as @code{"He said \"hi!\" to her."}). +Because the string is delimited by +double quotes, you need to escape any quote that is part of the string, in order to tell @command{awk} to keep processing the rest of the string. @end table @@ -4934,7 +4989,7 @@ leaves what happens as undefined. There are two choices: @cindex Brian Kernighan's @command{awk} @table @asis @item Strip the backslash out -This is what Brian Kernighan's @command{awk} and @command{gawk} both do. +This is what BWK @command{awk} and @command{gawk} both do. For example, @code{"a\qc"} is the same as @code{"aqc"}. (Because this is such an easy bug both to introduce and to miss, @command{gawk} warns you about it.) @@ -4987,7 +5042,7 @@ The escape sequences described @ifnotinfo earlier @end ifnotinfo -in @ref{Escape Sequences}, +in @DBREF{Escape Sequences} are valid inside a regexp. They are introduced by a @samp{\} and are recognized and converted into corresponding real characters as the very first step in processing regexps. @@ -5084,12 +5139,11 @@ or @samp{k}. @cindex vertical bar (@code{|}) @item @code{|} This is the @dfn{alternation operator} and it is used to specify -alternatives. -The @samp{|} has the lowest precedence of all the regular -expression operators. -For example, @samp{^P|[[:digit:]]} -matches any string that matches either @samp{^P} or @samp{[[:digit:]]}. This -means it matches any string that starts with @samp{P} or contains a digit. +alternatives. The @samp{|} has the lowest precedence of all the regular +expression operators. For example, @samp{^P|[aeiouy]} matches any string +that matches either @samp{^P} or @samp{[aeiouy]}. This means it matches +any string that starts with @samp{P} or contains (anywhere within it) +a lowercase English vowel. The alternation applies to the largest possible regexps on either side. @@ -5113,14 +5167,15 @@ applies the @samp{*} symbol to the preceding @samp{h} and looks for matches of one @samp{p} followed by any number of @samp{h}s. This also matches just @samp{p} if no @samp{h}s are present. -The @samp{*} repeats the @emph{smallest} possible preceding expression. -(Use parentheses if you want to repeat a larger expression.) It finds -as many repetitions as possible. For example, -@samp{awk '/\(c[ad][ad]*r x\)/ @{ print @}' sample} -prints every record in @file{sample} containing a string of the form -@samp{(car x)}, @samp{(cdr x)}, @samp{(cadr x)}, and so on. -Notice the escaping of the parentheses by preceding them -with backslashes. +There are two subtle points to understand about how @samp{*} works. +First, the @samp{*} applies only to the single preceding regular expression +component (e.g., in @samp{ph*}, it applies just to the @samp{h}). +To cause @samp{*} to apply to a larger sub-expression, use parentheses: +@samp{(ph)*} matches @samp{ph}, @samp{phph}, @samp{phphph} and so on. + +Second, @samp{*} finds as many repetititons as possible. If the text +to be matched is @samp{phhhhhhhhhhhhhhooey}, @samp{ph*} matches all of +the @samp{h}s. @cindex @code{+} (plus sign), regexp operator @cindex plus sign (@code{+}), regexp operator @@ -5129,12 +5184,6 @@ This symbol is similar to @samp{*}, except that the preceding expression must be matched at least once. This means that @samp{wh+y} would match @samp{why} and @samp{whhy}, but not @samp{wy}, whereas @samp{wh*y} would match all three. -The following is a simpler -way of writing the last @samp{*} example: - -@example -awk '/\(c[ad]+r x\)/ @{ print @}' sample -@end example @cindex @code{?} (question mark), regexp operator @cindex question mark (@code{?}), regexp operator @@ -5229,7 +5278,7 @@ Within a bracket expression, a @dfn{range expression} consists of two characters separated by a hyphen. It matches any single character that sorts between the two characters, based upon the system's native character set. For example, @samp{[0-9]} is equivalent to @samp{[0123456789]}. -(See @ref{Ranges and Locales}, for an explanation of how the POSIX +(See @DBREF{Ranges and Locales} for an explanation of how the POSIX standard and @command{gawk} have changed over time. This is mainly of historical interest.) @@ -5248,6 +5297,9 @@ bracket expression, put a @samp{\} in front of it. For example: @noindent matches either @samp{d} or @samp{]}. +Additionally, if you place @samp{]} right after the opening +@samp{[}, the closing bracket is treated as one of the +characters to be matched. @cindex POSIX @command{awk}, bracket expressions and @cindex Extended Regular Expressions (EREs) @@ -5359,6 +5411,160 @@ they do not recognize collating symbols or equivalence classes. @c maybe one day ... @c ENDOFRANGE charlist +@node Leftmost Longest +@section How Much Text Matches? + +@cindex regular expressions, leftmost longest match +@c @cindex matching, leftmost longest +Consider the following: + +@example +echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' +@end example + +This example uses the @code{sub()} function (which we haven't discussed yet; +@pxref{String Functions}) +to make a change to the input record. Here, the regexp @code{/a+/} +indicates ``one or more @samp{a} characters,'' and the replacement +text is @samp{<A>}. + +The input contains four @samp{a} characters. +@command{awk} (and POSIX) regular expressions always match +the leftmost, @emph{longest} sequence of input characters that can +match. Thus, all four @samp{a} characters are +replaced with @samp{<A>} in this example: + +@example +$ @kbd{echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'} +@print{} <A>bcd +@end example + +For simple match/no-match tests, this is not so important. But when doing +text matching and substitutions with the @code{match()}, @code{sub()}, @code{gsub()}, +and @code{gensub()} functions, it is very important. +@ifinfo +@xref{String Functions}, +for more information on these functions. +@end ifinfo +Understanding this principle is also important for regexp-based record +and field splitting (@pxref{Records}, +and also @pxref{Field Separators}). + +@node Computed Regexps +@section Using Dynamic Regexps + +@c STARTOFRANGE dregexp +@cindex regular expressions, computed +@c STARTOFRANGE regexpd +@cindex regular expressions, dynamic +@cindex @code{~} (tilde), @code{~} operator +@cindex tilde (@code{~}), @code{~} operator +@cindex @code{!} (exclamation point), @code{!~} operator +@cindex exclamation point (@code{!}), @code{!~} operator +@c @cindex operators, @code{~} +@c @cindex operators, @code{!~} +The righthand side of a @samp{~} or @samp{!~} operator need not be a +regexp constant (i.e., a string of characters between slashes). It may +be any expression. The expression is evaluated and converted to a string +if necessary; the contents of the string are then used as the +regexp. A regexp computed in this way is called a @dfn{dynamic +regexp} or a @dfn{computed regexp}: + +@example +BEGIN @{ digits_regexp = "[[:digit:]]+" @} +$0 ~ digits_regexp @{ print @} +@end example + +@noindent +This sets @code{digits_regexp} to a regexp that describes one or more digits, +and tests whether the input record matches this regexp. + +@quotation NOTE +When using the @samp{~} and @samp{!~} +operators, there is a difference between a regexp constant +enclosed in slashes and a string constant enclosed in double quotes. +If you are going to use a string constant, you have to understand that +the string is, in essence, scanned @emph{twice}: the first time when +@command{awk} reads your program, and the second time when it goes to +match the string on the lefthand side of the operator with the pattern +on the right. This is true of any string-valued expression (such as +@code{digits_regexp}, shown previously), not just string constants. +@end quotation + +@cindex regexp constants, slashes vs.@: quotes +@cindex @code{\} (backslash), in regexp constants +@cindex backslash (@code{\}), in regexp constants +@cindex @code{"} (double quote), in regexp constants +@cindex double quote (@code{"}), in regexp constants +What difference does it make if the string is +scanned twice? The answer has to do with escape sequences, and particularly +with backslashes. To get a backslash into a regular expression inside a +string, you have to type two backslashes. + +For example, @code{/\*/} is a regexp constant for a literal @samp{*}. +Only one backslash is needed. To do the same thing with a string, +you have to type @code{"\\*"}. The first backslash escapes the +second one so that the string actually contains the +two characters @samp{\} and @samp{*}. + +@cindex troubleshooting, regexp constants vs.@: string constants +@cindex regexp constants, vs.@: string constants +@cindex string constants, vs.@: regexp constants +Given that you can use both regexp and string constants to describe +regular expressions, which should you use? The answer is ``regexp +constants,'' for several reasons: + +@itemize @value{BULLET} +@item +String constants are more complicated to write and +more difficult to read. Using regexp constants makes your programs +less error-prone. Not understanding the difference between the two +kinds of constants is a common source of errors. + +@item +It is more efficient to use regexp constants. @command{awk} can note +that you have supplied a regexp and store it internally in a form that +makes pattern matching more efficient. When using a string constant, +@command{awk} must first convert the string into this internal form and +then perform the pattern matching. + +@item +Using regexp constants is better form; it shows clearly that you +intend a regexp match. +@end itemize + +@sidebar Using @code{\n} in Bracket Expressions of Dynamic Regexps +@cindex regular expressions, dynamic, with embedded newlines +@cindex newlines, in dynamic regexps + +Some versions of @command{awk} do not allow the newline +character to be used inside a bracket expression for a dynamic regexp: + +@example +$ @kbd{awk '$0 ~ "[ \t\n]"'} +@error{} awk: newline in character class [ +@error{} ]... +@error{} source line number 1 +@error{} context is +@error{} >>> <<< +@end example + +@cindex newlines, in regexp constants +But a newline in a regexp constant works with no problem: + +@example +$ @kbd{awk '$0 ~ /[ \t\n]/'} +@kbd{here is a sample line} +@print{} here is a sample line +@kbd{Ctrl-d} +@end example + +@command{gawk} does not have this problem, and it isn't likely to +occur often in practice, but it's worth noting for future reference. +@end sidebar +@c ENDOFRANGE dregexp +@c ENDOFRANGE regexpd + @node GNU Regexp Operators @section @command{gawk}-Specific Regexp Operators @@ -5522,7 +5728,7 @@ are allowed. Traditional Unix @command{awk} regexps are matched. The GNU operators are not special, and interval expressions are not available. The POSIX character classes (@samp{[[:alnum:]]}, etc.) are supported, -as Brian Kernighan's @command{awk} does support them. +as BWK @command{awk} does support them. Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. @@ -5634,160 +5840,6 @@ Case is always significant in compatibility mode. @c ENDOFRANGE csregexp @c ENDOFRANGE regexpcs -@node Leftmost Longest -@section How Much Text Matches? - -@cindex regular expressions, leftmost longest match -@c @cindex matching, leftmost longest -Consider the following: - -@example -echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}' -@end example - -This example uses the @code{sub()} function (which we haven't discussed yet; -@pxref{String Functions}) -to make a change to the input record. Here, the regexp @code{/a+/} -indicates ``one or more @samp{a} characters,'' and the replacement -text is @samp{<A>}. - -The input contains four @samp{a} characters. -@command{awk} (and POSIX) regular expressions always match -the leftmost, @emph{longest} sequence of input characters that can -match. Thus, all four @samp{a} characters are -replaced with @samp{<A>} in this example: - -@example -$ @kbd{echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'} -@print{} <A>bcd -@end example - -For simple match/no-match tests, this is not so important. But when doing -text matching and substitutions with the @code{match()}, @code{sub()}, @code{gsub()}, -and @code{gensub()} functions, it is very important. -@ifinfo -@xref{String Functions}, -for more information on these functions. -@end ifinfo -Understanding this principle is also important for regexp-based record -and field splitting (@pxref{Records}, -and also @pxref{Field Separators}). - -@node Computed Regexps -@section Using Dynamic Regexps - -@c STARTOFRANGE dregexp -@cindex regular expressions, computed -@c STARTOFRANGE regexpd -@cindex regular expressions, dynamic -@cindex @code{~} (tilde), @code{~} operator -@cindex tilde (@code{~}), @code{~} operator -@cindex @code{!} (exclamation point), @code{!~} operator -@cindex exclamation point (@code{!}), @code{!~} operator -@c @cindex operators, @code{~} -@c @cindex operators, @code{!~} -The righthand side of a @samp{~} or @samp{!~} operator need not be a -regexp constant (i.e., a string of characters between slashes). It may -be any expression. The expression is evaluated and converted to a string -if necessary; the contents of the string are then used as the -regexp. A regexp computed in this way is called a @dfn{dynamic -regexp} or a @dfn{computed regexp}: - -@example -BEGIN @{ digits_regexp = "[[:digit:]]+" @} -$0 ~ digits_regexp @{ print @} -@end example - -@noindent -This sets @code{digits_regexp} to a regexp that describes one or more digits, -and tests whether the input record matches this regexp. - -@quotation NOTE -When using the @samp{~} and @samp{!~} -operators, there is a difference between a regexp constant -enclosed in slashes and a string constant enclosed in double quotes. -If you are going to use a string constant, you have to understand that -the string is, in essence, scanned @emph{twice}: the first time when -@command{awk} reads your program, and the second time when it goes to -match the string on the lefthand side of the operator with the pattern -on the right. This is true of any string-valued expression (such as -@code{digits_regexp}, shown previously), not just string constants. -@end quotation - -@cindex regexp constants, slashes vs.@: quotes -@cindex @code{\} (backslash), in regexp constants -@cindex backslash (@code{\}), in regexp constants -@cindex @code{"} (double quote), in regexp constants -@cindex double quote (@code{"}), in regexp constants -What difference does it make if the string is -scanned twice? The answer has to do with escape sequences, and particularly -with backslashes. To get a backslash into a regular expression inside a -string, you have to type two backslashes. - -For example, @code{/\*/} is a regexp constant for a literal @samp{*}. -Only one backslash is needed. To do the same thing with a string, -you have to type @code{"\\*"}. The first backslash escapes the -second one so that the string actually contains the -two characters @samp{\} and @samp{*}. - -@cindex troubleshooting, regexp constants vs.@: string constants -@cindex regexp constants, vs.@: string constants -@cindex string constants, vs.@: regexp constants -Given that you can use both regexp and string constants to describe -regular expressions, which should you use? The answer is ``regexp -constants,'' for several reasons: - -@itemize @value{BULLET} -@item -String constants are more complicated to write and -more difficult to read. Using regexp constants makes your programs -less error-prone. Not understanding the difference between the two -kinds of constants is a common source of errors. - -@item -It is more efficient to use regexp constants. @command{awk} can note -that you have supplied a regexp and store it internally in a form that -makes pattern matching more efficient. When using a string constant, -@command{awk} must first convert the string into this internal form and -then perform the pattern matching. - -@item -Using regexp constants is better form; it shows clearly that you -intend a regexp match. -@end itemize - -@sidebar Using @code{\n} in Bracket Expressions of Dynamic Regexps -@cindex regular expressions, dynamic, with embedded newlines -@cindex newlines, in dynamic regexps - -Some versions of @command{awk} do not allow the newline -character to be used inside a bracket expression for a dynamic regexp: - -@example -$ @kbd{awk '$0 ~ "[ \t\n]"'} -@error{} awk: newline in character class [ -@error{} ]... -@error{} source line number 1 -@error{} context is -@error{} >>> <<< -@end example - -@cindex newlines, in regexp constants -But a newline in a regexp constant works with no problem: - -@example -$ @kbd{awk '$0 ~ /[ \t\n]/'} -@kbd{here is a sample line} -@print{} here is a sample line -@kbd{Ctrl-d} -@end example - -@command{gawk} does not have this problem, and it isn't likely to -occur often in practice, but it's worth noting for future reference. -@end sidebar -@c ENDOFRANGE dregexp -@c ENDOFRANGE regexpd - @node Regexp Summary @section Summary @@ -5798,7 +5850,7 @@ In @command{awk}, regular expression constants are written enclosed between slashes: @code{/}@dots{}@code{/}. @item -Regexp constants may be used by standalone in patterns and +Regexp constants may be used standalone in patterns and in conditional expressions, or as part of matching expressions using the @samp{~} and @samp{!~} operators. @@ -5828,7 +5880,7 @@ the match, such as for text substitution and when the record separator is a regexp. @item -Matching expressions may use dynamic regexps; that is string values +Matching expressions may use dynamic regexps, that is, string values treated as regular expressions. @end itemize @@ -5880,7 +5932,7 @@ used with it do not have to be named on the @command{awk} command line * Getline:: Reading files under explicit program control using the @code{getline} function. * Read Timeout:: Reading input with a timeout. -* Command line directories:: What happens if you put a directory on the +* Command-line directories:: What happens if you put a directory on the command line. * Input Summary:: Input summary. * Input Exercises:: Exercises. @@ -5895,16 +5947,13 @@ used with it do not have to be named on the @command{awk} command line @cindex records, splitting input into @cindex @code{NR} variable @cindex @code{FNR} variable -The @command{awk} utility divides the input for your @command{awk} -program into records and fields. -@command{awk} keeps track of the number of records that have -been read -so far -from the current input file. This value is stored in a -built-in variable called @code{FNR}. It is reset to zero when a new -file is started. Another built-in variable, @code{NR}, records the total -number of input records read so far from all @value{DF}s. It starts at zero, -but is never automatically reset to zero. +@command{awk} divides the input for your program into records and fields. +It keeps track of the number of records that have been read so far from +the current input file. This value is stored in a built-in variable +called @code{FNR} which is reset to zero when a new file is started. +Another built-in variable, @code{NR}, records the total number of input +records read so far from all @value{DF}s. It starts at zero, but is +never automatically reset to zero. @menu * awk split records:: How standard @command{awk} splits records. @@ -6111,17 +6160,17 @@ with optional leading and/or trailing whitespace: @example $ @kbd{echo record 1 AAAA record 2 BBBB record 3 |} > @kbd{gawk 'BEGIN @{ RS = "\n|( *[[:upper:]]+ *)" @}} -> @kbd{@{ print "Record =", $0, "and RT =", RT @}'} -@print{} Record = record 1 and RT = AAAA -@print{} Record = record 2 and RT = BBBB -@print{} Record = record 3 and RT = -@print{} +> @kbd{@{ print "Record =", $0,"and RT = [" RT "]" @}'} +@print{} Record = record 1 and RT = [ AAAA ] +@print{} Record = record 2 and RT = [ BBBB ] +@print{} Record = record 3 and RT = [ +@print{} ] @end example @noindent -The final line of output has an extra blank line. This is because the -value of @code{RT} is a newline, and the @code{print} statement -supplies its own terminating newline. +The square brackets delineate the contents of @code{RT}, letting you +see the leading and trailing whitespace. The final value of @code{RT} +@code{RT} is a newline. @xref{Simple Sed}, for a more useful example of @code{RS} as a regexp and @code{RT}. @@ -6548,7 +6597,7 @@ with a statement such as @samp{$1 = $1}, as described earlier. * Default Field Splitting:: How fields are normally separated. * Regexp Field Splitting:: Using regexps as the field separator. * Single Character Fields:: Making each character a separate field. -* Command Line Field Separator:: Setting @code{FS} from the command-line. +* Command Line Field Separator:: Setting @code{FS} from the command line. * Full Line Fields:: Making the full line be a single field. * Field Splitting Summary:: Some final points and a summary table. @end menu @@ -6749,7 +6798,7 @@ should not rely on any specific behavior in your programs. @value{DARKCORNER} @cindex Brian Kernighan's @command{awk} -As a point of information, Brian Kernighan's @command{awk} allows @samp{^} +As a point of information, BWK @command{awk} allows @samp{^} to match only at the beginning of the record. @command{gawk} also works this way. For example: @@ -6804,7 +6853,7 @@ behaves this way. @node Command Line Field Separator @subsection Setting @code{FS} from the Command Line -@cindex @option{-F} option, command line +@cindex @option{-F} option, command-line @cindex field separator, on command line @cindex command line, @code{FS} on@comma{} setting @cindex @code{FS} variable, setting from command line @@ -6854,6 +6903,8 @@ shell, without any quotes, the @samp{\} gets deleted, so @command{awk} figures that you really want your fields to be separated with TABs and not @samp{t}s. Use @samp{-v FS="t"} or @samp{-F"[t]"} on the command line if you really do want to separate your fields with @samp{t}s. +Use @samp{-F '\t'} when not in compatibility mode to specify that TABs +separate fields. As an example, let's use an @command{awk} program file called @file{edu.awk} that contains the pattern @code{/edu/} and the action @samp{print $1}: @@ -6999,7 +7050,7 @@ root @noindent on an incorrect implementation of @command{awk}, while @command{gawk} -prints something like: +prints the full first line of the file, something like: @example root:nSijPlPhZZwgE:0:0:Root:/: @@ -7099,7 +7150,7 @@ haven't been introduced yet. BEGIN @{ FIELDWIDTHS = "9 6 10 6 7 7 35" @} NR > 2 @{ idle = $4 - sub(/^ */, "", idle) # strip leading spaces + sub(/^ +/, "", idle) # strip leading spaces if (idle == "") idle = 0 if (idle ~ /:/) @{ @@ -7257,6 +7308,8 @@ if (substr($i, 1, 1) == "\"") @{ As with @code{FS}, the @code{IGNORECASE} variable (@pxref{User-modified}) affects field splitting with @code{FPAT}. +Assigning a value to @code{FPAT} overrides field splitting +with @code{FS} and with @code{FIELDWIDTHS}. Similar to @code{FIELDWIDTHS}, the value of @code{PROCINFO["FS"]} will be @code{"FPAT"} if content-based field splitting is being used. @@ -7280,6 +7333,12 @@ FPAT = "([^,]*)|(\"[^\"]+\")" Finally, the @code{patsplit()} function makes the same functionality available for splitting regular strings (@pxref{String Functions}). +To recap, @command{gawk} provides three independent methods +to split input records into fields. @command{gawk} uses whichever +mechanism was last chosen based on which of the three +variables---@code{FS}, @code{FIELDWIDTHS}, and @code{FPAT}---was +last assigned to. + @node Multiple Line @section Multiple-Line Records @@ -7501,7 +7560,7 @@ and have a good knowledge of how @command{awk} works. @cindex @code{getline} command, return values @cindex @option{--sandbox} option, input redirection with @code{getline} -The @code{getline} command returns one if it finds a record and zero if +The @code{getline} command returns 1 if it finds a record and 0 if it encounters the end of the file. If there is some error in getting a record, such as a file that cannot be opened, then @code{getline} returns @minus{}1. In this case, @command{gawk} sets the variable @@ -7541,32 +7600,58 @@ finished processing the current record, but want to do some special processing on the next record @emph{right now}. For example: @example +# Remove text between /* and */, inclusive @{ - if ((t = index($0, "/*")) != 0) @{ - # value of `tmp' will be "" if t is 1 - tmp = substr($0, 1, t - 1) - u = index(substr($0, t + 2), "*/") - offset = t + 2 - while (u == 0) @{ - if (getline <= 0) @{ + if ((i = index($0, "/*")) != 0) @{ + out = substr($0, 1, i - 1) # leading part of the string + rest = substr($0, i + 2) # ... */ ... + j = index(rest, "*/") # is */ in trailing part? + if (j > 0) @{ + rest = substr(rest, j + 2) # remove comment + @} else @{ + while (j == 0) @{ + # get more text + if (getline <= 0) @{ m = "unexpected EOF or error" m = (m ": " ERRNO) print m > "/dev/stderr" exit - @} - u = index($0, "*/") - offset = 0 - @} - # substr() expression will be "" if */ - # occurred at end of line - $0 = tmp substr($0, offset + u + 2) - @} - print $0 + @} + # build up the line using string concatenation + rest = rest $0 + j = index(rest, "*/") # is */ in trailing part? + if (j != 0) @{ + rest = substr(rest, j + 2) + break + @} + @} + @} + # build up the output line using string concatenation + $0 = out rest + @} + print $0 @} @end example +@c 8/2014: Here is some sample input: +@ignore +mon/*comment*/key +rab/*commen +t*/bit +horse /*comment*/more text +part 1 /*comment*/part 2 /*comment*/part 3 +no comment +@end ignore + This @command{awk} program deletes C-style comments (@samp{/* @dots{} -*/}) from the input. By replacing the @samp{print $0} with other +*/}) from the input. +It uses a number of features we haven't covered yet, including +string concatenation +(@pxref{Concatenation}) +and the @code{index()} and @code{substr()} built-in +functions +(@pxref{String Functions}). +By replacing the @samp{print $0} with other statements, you could perform more complicated processing on the decommented input, such as searching for matches of a regular expression. (This program has a subtle problem---it does not work if one @@ -7823,7 +7908,7 @@ Unfortunately, @command{gawk} has not been consistent in its treatment of a construct like @samp{@w{"echo "} "date" | getline}. Most versions, including the current version, treat it at as @samp{@w{("echo "} "date") | getline}. -(This how Brian Kernighan's @command{awk} behaves.) +(This how BWK @command{awk} behaves.) Some versions changed and treated it as @samp{@w{"echo "} ("date" | getline)}. (This is how @command{mawk} behaves.) @@ -7973,7 +8058,7 @@ probably by accident, and you should reconsider what it is you're trying to accomplish. @item -@ref{Getline Summary}, presents a table summarizing the +@DBREF{Getline Summary} presents a table summarizing the @code{getline} variants and which variables they can affect. It is worth noting that those variants which do not use redirection can cause @code{FILENAME} to be updated if they cause @@ -8144,10 +8229,10 @@ a connection before it can start reading any data, or the attempt to open a FIFO special file for reading can block indefinitely until some other process opens it for writing. -@node Command line directories +@node Command-line directories @section Directories On The Command Line -@cindex differences in @command{awk} and @command{gawk}, command line directories -@cindex directories, command line +@cindex differences in @command{awk} and @command{gawk}, command-line directories +@cindex directories, command-line @cindex command line, directories on According to the POSIX standard, files named on the @command{awk} @@ -8240,6 +8325,7 @@ Directories on the command line are fatal for standard @command{awk}; @end itemize +@c EXCLUDE START @node Input Exercises @section Exercises @@ -8256,9 +8342,10 @@ including abstentions, for each item. comments (@samp{/* @dots{} */}) from the input. That program does not work if one comment ends on one line and another one starts later on the same line. -Write a program that does handle multiple comments on the line. +That can be fixed by making one simple change. What is it? @end enumerate +@c EXCLUDE END @node Printing @chapter Printing Output @@ -8300,7 +8387,7 @@ and discusses the @code{close()} built-in function. descriptors. * Close Files And Pipes:: Closing Input and Output Files and Pipes. * Output Summary:: Output summary. -* Output exercises:: Exercises. +* Output Exercises:: Exercises. @end menu @node Print @@ -8337,6 +8424,10 @@ double-quote characters, your text is taken as an @command{awk} expression, and you will probably get an error. Keep in mind that a space is printed between any two items. +Note that the @code{print} statement is a statement and not an +expression---you can't use it the pattern part of a pattern-action +statement, for example. + @node Print Examples @section @code{print} Statement Examples @@ -9272,7 +9363,7 @@ It then sends the list to the shell for execution. @c ENDOFRANGE reout @node Special Files -@section Special @value{FFN} in @command{gawk} +@section Special @value{FFN}s in @command{gawk} @c STARTOFRANGE gfn @cindex @command{gawk}, file names in @@ -9319,7 +9410,8 @@ print "Serious error detected!" | "cat 1>&2" @noindent This works by opening a pipeline to a shell command that can access the standard error stream that it inherits from the @command{awk} process. -This is far from elegant, and it is also inefficient, because it requires a +@c 8/2014: Mike Brennan says not to cite this as inefficient. So, fixed. +This is far from elegant, and it also requires a separate process. So people writing @command{awk} programs often don't do this. Instead, they send the error messages to the screen, like this: @@ -9706,7 +9798,8 @@ communications. @end itemize -@node Output exercises +@c EXCLUDE START +@node Output Exercises @section Exercises @enumerate @@ -9735,6 +9828,7 @@ BEGIN @{ print "Serious error detected!" > /dev/stderr @} @end example @end enumerate +@c EXCLUDE END @c ENDOFRANGE prnt @@ -9949,7 +10043,8 @@ A regexp constant is a regular expression description enclosed in slashes, such as @code{@w{/^beginning and end$/}}. Most regexps used in @command{awk} programs are constant, but the @samp{~} and @samp{!~} matching operators can also match computed or dynamic regexps -(which are just ordinary strings or variables that contain a regexp). +(which are typically just ordinary strings or variables that contain a regexp, +but could be a more complex expression). @c ENDOFRANGE cnst @node Using Constant Regexps @@ -10055,7 +10150,7 @@ function mysub(pat, repl, str, global) @c @cindex automatic warnings @c @cindex warnings, automatic In this example, the programmer wants to pass a regexp constant to the -user-defined function @code{mysub}, which in turn passes it on to +user-defined function @code{mysub()}, which in turn passes it on to either @code{sub()} or @code{gsub()}. However, what really happens is that the @code{pat} parameter is either one or zero, depending upon whether or not @code{$0} matches @code{/hi/}. @@ -10076,7 +10171,7 @@ on the @command{awk} command line. @menu * Using Variables:: Using variables in your programs. -* Assignment Options:: Setting variables on the command-line and a +* Assignment Options:: Setting variables on the command line and a summary of command-line syntax. This is an advanced method of input. @end menu @@ -10534,7 +10629,7 @@ print "something meaningful" > file name @cindex @command{mawk} utility @noindent This produces a syntax error with some versions of Unix -@command{awk}.@footnote{It happens that Brian Kernighan's +@command{awk}.@footnote{It happens that BWK @command{awk}, @command{gawk} and @command{mawk} all ``get it right,'' but you should not rely on this.} It is necessary to use the following: @@ -10619,7 +10714,7 @@ Otherwise, it's parsed as follows: @end display As mentioned earlier, -when doing concatenation, @emph{parenthesize}. Otherwise, +when mixing concatenation with other operators, @emph{parenthesize}. Otherwise, you're never quite sure what you'll get. @node Assignment Ops @@ -10872,7 +10967,7 @@ A workaround is: awk '/[=]=/' /dev/null @end example -@command{gawk} does not have this problem; Brian Kernighan's @command{awk} +@command{gawk} does not have this problem; BWK @command{awk} and @command{mawk} also do not (@pxref{Other Versions}). @end sidebar @c ENDOFRANGE exas @@ -11105,19 +11200,14 @@ compares variables. @cindex numeric, strings @cindex strings, numeric @cindex POSIX @command{awk}, numeric strings and -The 1992 POSIX standard introduced +The POSIX standard introduced the concept of a @dfn{numeric string}, which is simply a string that looks like a number---for example, @code{@w{" +2"}}. This concept is used for determining the type of a variable. The type of the variable is important because the types of two variables determine how they are compared. +Variable typing follows these rules: -The various versions of the POSIX standard did not get the rules -quite right for several editions. Fortunately, as of at least the -2008 standard (and possibly earlier), the standard has been fixed, -and variable typing follows these rules:@footnote{@command{gawk} has -followed these rules for many years, -and it is gratifying that the POSIX standard is also now correct.} @itemize @value{BULLET} @item @@ -11270,7 +11360,7 @@ made of characters and is therefore also a string. Thus, for example, the string constant @w{@code{" +3.14"}}, when it appears in program source code, is a string---even though it looks numeric---and -is @emph{never} treated as number for comparison +is @emph{never} treated as a number for comparison purposes. In short, when one operand is a ``pure'' string, such as a string @@ -11587,7 +11677,7 @@ is ``short-circuited'' if the result can be determined part way through its evaluation. @cindex line continuations -Statements that use @samp{&&} or @samp{||} can be continued simply +Statements that end with @samp{&&} or @samp{||} can be continued simply by putting a newline after them. But you cannot put a newline in front of either of these operators without using backslash continuation (@pxref{Statements/Lines}). @@ -11606,7 +11696,7 @@ program is one way to print lines in between special bracketing lines: @example $1 == "START" @{ interested = ! interested; next @} -interested == 1 @{ print @} +interested @{ print @} $1 == "END" @{ interested = ! interested; next @} @end example @@ -11626,6 +11716,16 @@ bogus input data, but the point is to illustrate the use of `!', so we'll leave well enough alone. @end ignore +Most commonly, the @samp{!} operator is used in the conditions of +@code{if} and @code{while} statements, where it often makes more +sense to phrase the logic in the negative: + +@example +if (! @var{some condition} || @var{some other condition}) @{ + @var{@dots{} do whatever processing @dots{}} +@} +@end example + @cindex @code{next} statement @quotation NOTE The @code{next} statement is discussed in @@ -12246,7 +12346,7 @@ Contrast this with the following regular expression match, which accepts any record with a first field that contains @samp{li}: @example -$ @kbd{awk '$1 ~ /foo/ @{ print $2 @}' mail-list} +$ @kbd{awk '$1 ~ /li/ @{ print $2 @}' mail-list} @print{} 555-5553 @print{} 555-6699 @end example @@ -12518,7 +12618,7 @@ rule. It contains the number of fields from the last input record. Most probably due to an oversight, the standard does not say that @code{$0} is also preserved, although logically one would think that it should be. In fact, @command{gawk} does preserve the value of @code{$0} for use in -@code{END} rules. Be aware, however, that Brian Kernighan's @command{awk}, and possibly +@code{END} rules. Be aware, however, that BWK @command{awk}, and possibly other implementations, do not. The third point follows from the first two. The meaning of @samp{print} @@ -13157,31 +13257,38 @@ case is made, the case statement bodies execute until a @code{break}, or the end of the @code{switch} statement itself. For example: @example -switch (NR * 2 + 1) @{ -case 3: -case "11": - print NR - 1 - break - -case /2[[:digit:]]+/: - print NR - -default: - print NR + 1 - -case -1: - print NR * -1 +while ((c = getopt(ARGC, ARGV, "aksx")) != -1) @{ + switch (c) @{ + case "a": + # report size of all files + all_files = TRUE; + break + case "k": + BLOCK_SIZE = 1024 # 1K block size + break + case "s": + # do sums only + sum_only = TRUE + break + case "x": + # don't cross filesystems + fts_flags = or(fts_flags, FTS_XDEV) + break + case "?": + default: + usage() + break + @} @} @end example Note that if none of the statements specified above halt execution of a matched @code{case} statement, execution falls through to the -next @code{case} until execution halts. In the above example, for -any case value starting with @samp{2} followed by one or more digits, -the @code{print} statement is executed and then falls through into the -@code{default} section, executing its @code{print} statement. In turn, -the @minus{}1 case will also be executed since the @code{default} does -not halt execution. +next @code{case} until execution halts. In the above example, the +@code{case} for @code{"?"} falls through to the @code{default} +case, which is to call a function named @code{usage()}. +(The @code{getopt()} function being called here is +described in @ref{Getopt Function}.) @node Break Statement @subsection The @code{break} Statement @@ -13255,7 +13362,7 @@ historical implementations of @command{awk} treated the @code{break} statement outside of a loop as if it were a @code{next} statement (@pxref{Next Statement}). @value{DARKCORNER} -Recent versions of Brian Kernighan's @command{awk} no longer allow this usage, +Recent versions of BWK @command{awk} no longer allow this usage, nor does @command{gawk}. @node Continue Statement @@ -13304,7 +13411,8 @@ BEGIN @{ @end example @noindent -This program loops forever once @code{x} reaches 5. +This program loops forever once @code{x} reaches 5, since +the increment (@samp{x++}) is never reached. @c @cindex @code{continue}, outside of loops @c @cindex historical features @@ -13321,7 +13429,7 @@ statement outside a loop: as if it were a @code{next} statement (@pxref{Next Statement}). @value{DARKCORNER} -Recent versions of Brian Kernighan's @command{awk} no longer work this way, nor +Recent versions of BWK @command{awk} no longer work this way, nor does @command{gawk}. @node Next Statement @@ -13410,7 +13518,8 @@ starts over with the first rule in the program. If the @code{nextfile} statement causes the end of the input to be reached, then the code in any @code{END} rules is executed. An exception to this is when @code{nextfile} is invoked during execution of any statement in an -@code{END} rule; In this case, it causes the program to stop immediately. @xref{BEGIN/END}. +@code{END} rule; in this case, it causes the program to stop immediately. +@xref{BEGIN/END}. The @code{nextfile} statement is useful when there are many @value{DF}s to process but it isn't necessary to process every record in every file. @@ -13420,13 +13529,10 @@ would have to continue scanning the unwanted records. The @code{nextfile} statement accomplishes this much more efficiently. In @command{gawk}, execution of @code{nextfile} causes additional things -to happen: -any @code{ENDFILE} rules are executed except in the case as -mentioned below, -@code{ARGIND} is incremented, -and -any @code{BEGINFILE} rules are executed. -(@code{ARGIND} hasn't been introduced yet. @xref{Built-in Variables}.) +to happen: any @code{ENDFILE} rules are executed if @command{gawk} is +not currently in an @code{END} or @code{BEGINFILE} rule, @code{ARGIND} is +incremented, and any @code{BEGINFILE} rules are executed. (@code{ARGIND} +hasn't been introduced yet. @xref{Built-in Variables}.) With @command{gawk}, @code{nextfile} is useful inside a @code{BEGINFILE} rule to skip over a file that would otherwise cause @command{gawk} @@ -13450,7 +13556,7 @@ See @uref{http://austingroupbugs.net/view.php?id=607, the Austin Group website}. @cindex @code{nextfile} statement, user-defined functions and @cindex Brian Kernighan's @command{awk} @cindex @command{mawk} utility -The current version of the Brian Kernighan's @command{awk}, and @command{mawk} (@pxref{Other +The current version of BWK @command{awk}, and @command{mawk} (@pxref{Other Versions}) also support @code{nextfile}. However, they don't allow the @code{nextfile} statement inside function bodies (@pxref{User-defined}). @command{gawk} does; a @code{nextfile} inside a function body reads the @@ -13959,7 +14065,7 @@ current record. @xref{Changing Fields}. @cindex differences in @command{awk} and @command{gawk}, @code{FUNCTAB} variable @item @code{FUNCTAB #} An array whose indices and corresponding values are the names of all -the user-defined or extension functions in the program. +the built-in, user-defined and extension functions in the program. @quotation NOTE Attempting to use the @code{delete} statement with the @code{FUNCTAB} @@ -14007,9 +14113,12 @@ text of the AWK program. For each identifier, the value of the element is one o @item "array" The identifier is an array. +@item "builtin" +The identifier is a built-in function. + @item "extension" The identifier is an extension function loaded via -@code{@@load}. +@code{@@load} or @option{-l}. @item "scalar" The identifier is a scalar. @@ -14243,7 +14352,7 @@ changed. @cindex arguments, command-line @cindex command line, arguments -@ref{Auto-set}, +@DBREF{Auto-set} presented the following program describing the information contained in @code{ARGC} and @code{ARGV}: @@ -14316,8 +14425,17 @@ before actual processing of the input begins. @xref{Split Program}, and see @ref{Tee Program}, for examples of each way of removing elements from @code{ARGV}. + +To actually get options into an @command{awk} program, +end the @command{awk} options with @option{--} and then supply +the @command{awk} program's options, in the following manner: + +@example +awk -f myprog.awk -- -v -q file1 file2 @dots{} +@end example + The following fragment processes @code{ARGV} in order to examine, and -then remove, command-line options: +then remove, the above command-line options: @example BEGIN @{ @@ -14337,32 +14455,24 @@ BEGIN @{ @} @end example -To actually get the options into the @command{awk} program, -end the @command{awk} options with @option{--} and then supply -the @command{awk} program's options, in the following manner: - -@example -awk -f myprog -- -v -q file1 file2 @dots{} -@end example - @cindex differences in @command{awk} and @command{gawk}, @code{ARGC}/@code{ARGV} variables -This is not necessary in @command{gawk}. Unless @option{--posix} has +Ending the @command{awk} options with @option{--} isn't +necessary in @command{gawk}. Unless @option{--posix} has been specified, @command{gawk} silently puts any unrecognized options into @code{ARGV} for the @command{awk} program to deal with. As soon as it sees an unknown option, @command{gawk} stops looking for other -options that it might otherwise recognize. The previous example with +options that it might otherwise recognize. The previous command line with @command{gawk} would be: @example -gawk -f myprog -q -v file1 file2 @dots{} +gawk -f myprog.awk -q -v file1 file2 @dots{} @end example @noindent -Because @option{-q} is not a valid @command{gawk} option, -it and the following @option{-v} -are passed on to the @command{awk} program. -(@xref{Getopt Function}, for an @command{awk} library function -that parses command-line options.) +Because @option{-q} is not a valid @command{gawk} option, it and the +following @option{-v} are passed on to the @command{awk} program. +(@xref{Getopt Function}, for an @command{awk} library function that +parses command-line options.) @node Pattern Action Summary @section Summary @@ -14617,7 +14727,10 @@ array element value: @end docbook @noindent -The pairs are shown in jumbled order because their order is irrelevant. +The pairs are shown in jumbled order because their order is +irrelevant.@footnote{The ordering will vary among @command{awk} +implementations, which typically use hash tables to store array elements +and values.} One advantage of associative arrays is that new pairs can be added at any time. For example, suppose a tenth element is added to the array @@ -14739,8 +14852,9 @@ English to French: Here we decided to translate the number one in both spelled-out and numeric form---thus illustrating that a single array can have both numbers and strings as indices. -(In fact, array subscripts are always strings; this is discussed -in more detail in +(In fact, array subscripts are always strings. +There are some subtleties to how numbers work when used as +array subscripts; this is discussed in more detail in @ref{Numeric Array Subscripts}.) Here, the number @code{1} isn't double-quoted, since @command{awk} automatically converts it to a string. @@ -14807,8 +14921,9 @@ if (a["foo"] != "") @dots{} @end example @noindent -This is incorrect, since this will @emph{create} @code{a["foo"]} -if it didn't exist before! +This is incorrect for two reasons. First, it @emph{creates} @code{a["foo"]} +if it didn't exist before! Second, it is valid (if a bit unusual) to set +an array element equal to the empty string. @end quotation @c @cindex arrays, @code{in} operator and @@ -14826,6 +14941,8 @@ This expression tests whether the particular index @var{indx} exists, without the side effect of creating that element if it is not present. The expression has the value one (true) if @code{@var{array}[@var{indx}]} exists and zero (false) if it does not exist. +(We use @var{indx} here, since @samp{index} is the name of a built-in +function.) For example, this statement tests whether the array @code{frequencies} contains the index @samp{2}: @@ -15033,7 +15150,7 @@ $ @kbd{gawk -f loopcheck.awk} @print{} is @end example -Contrast this to Brian Kernighan's @command{awk}: +Contrast this to BWK @command{awk}: @example $ @kbd{nawk -f loopcheck.awk} @@ -15278,7 +15395,7 @@ using @code{delete} without a subscript was a @command{gawk} extension. As of September, 2012, it was accepted for inclusion into the POSIX standard. See @uref{http://austingroupbugs.net/view.php?id=544, the Austin Group website}. This form of the @code{delete} statement is also supported -by Brian Kernighan's @command{awk} and @command{mawk}, as well as +by BWK @command{awk} and @command{mawk}, as well as by a number of other implementations (@pxref{Other Versions}). @end quotation @@ -15394,7 +15511,7 @@ $ @kbd{echo 'line 1} > @kbd{line 2} > @kbd{line 3' | awk '@{ l[lines] = $0; ++lines @}} > @kbd{END @{} -> @kbd{for (i = lines-1; i >= 0; --i)} +> @kbd{for (i = lines - 1; i >= 0; i--)} > @kbd{print l[i]} > @kbd{@}'} @print{} line 3 @@ -15418,7 +15535,7 @@ The following version of the program works correctly: @example @{ l[lines++] = $0 @} END @{ - for (i = lines - 1; i >= 0; --i) + for (i = lines - 1; i >= 0; i--) print l[i] @} @end example @@ -15492,10 +15609,11 @@ used for single dimensional arrays. Write the whole sequence of indices in parentheses, separated by commas, as the left operand: @example -(@var{subscript1}, @var{subscript2}, @dots{}) in @var{array} +if ((@var{subscript1}, @var{subscript2}, @dots{}) in @var{array}) + @dots{} @end example -The following example treats its input as a two-dimensional array of +Here is an example that treats its input as a two-dimensional array of fields; it rotates this array 90 degrees clockwise and prints the result. It assumes that all lines have the same number of elements: @@ -15968,7 +16086,9 @@ is @minus{}3, and @code{int(-3)} is @minus{}3 as well. @cindexawkfunc{log} @cindex logarithm Return the natural logarithm of @var{x}, if @var{x} is positive; -otherwise, report an error. +otherwise, return @code{NaN} (``not a number'') on IEEE 754 systems. +Additionally, @command{gawk} prints a warning message when @code{x} +is negative. @item @code{rand()} @cindexawkfunc{rand} @@ -16067,6 +16187,9 @@ numbers that are truly unpredictable. The return value of @code{srand()} is the previous seed. This makes it easy to keep track of the seeds in case you need to consistently reproduce sequences of random numbers. + +POSIX does not specify the initial seed; it differs among @command{awk} +implementations. @end table @node String Functions @@ -16742,7 +16865,7 @@ in the string, counting from character @var{start}. @cindex Brian Kernighan's @command{awk} If @var{start} is less than one, @code{substr()} treats it as if it was one. (POSIX doesn't specify what to do in this case: -Brian Kernighan's @command{awk} acts this way, and therefore @command{gawk} +BWK @command{awk} acts this way, and therefore @command{gawk} does too.) If @var{start} is greater than the number of characters in the string, @code{substr()} returns the null string. @@ -16811,6 +16934,12 @@ Nonalphabetic characters are left unchanged. For example, @cindex backslash (@code{\}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @cindex @code{&} (ampersand), @code{gsub()}/@code{gensub()}/@code{sub()} functions and @cindex ampersand (@code{&}), @code{gsub()}/@code{gensub()}/@code{sub()} functions and + +@quotation CAUTION +This section has been known to cause headaches. +You might want to skip it upon first reading. +@end quotation + When using @code{sub()}, @code{gsub()}, or @code{gensub()}, and trying to get literal backslashes and ampersands into the replacement text, you need to remember that there are several levels of @dfn{escape processing} going on. @@ -16828,7 +16957,7 @@ escape sequences listed in @ref{Escape Sequences}. Thus, for every @samp{\} that @command{awk} processes at the runtime level, you must type two backslashes at the lexical level. When a character that is not valid for an escape sequence follows the -@samp{\}, Brian Kernighan's @command{awk} and @command{gawk} both simply remove the initial +@samp{\}, BWK @command{awk} and @command{gawk} both simply remove the initial @samp{\} and put the next character into the string. Thus, for example, @code{"a\qb"} is treated as @code{"aqb"}. @@ -16853,26 +16982,26 @@ through unchanged. This is illustrated in @ref{table-sub-escapes}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr - @code{\&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\\&}! @code{\\&}!a literal @samp{\&}_cr - @code{\\\\\&}! @code{\\&}!a literal @samp{\&}_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\\&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr + @code{\&}! @code{&}!The matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\\&}! @code{\\&}!A literal @samp{\&}_cr + @code{\\\\\&}! @code{\\&}!A literal @samp{\&}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\\&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr } _bigskip} @end tex @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\&} -@item @code{\\\\\&} @tab @code{\\&} @tab a literal @samp{\&} -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\\&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\&} @tab @code{&} @tab The matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\&} +@item @code{\\\\\&} @tab @code{\\&} @tab A literal @samp{\&} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\\&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @end multitable @end ifdocbook @ifnottex @@ -16880,13 +17009,13 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- - @code{\&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\&} @code{\&} a literal @samp{&} - @code{\\\\&} @code{\\&} a literal @samp{\&} - @code{\\\\\&} @code{\\&} a literal @samp{\&} -@code{\\\\\\&} @code{\\\&} a literal @samp{\\&} - @code{\\q} @code{\q} a literal @samp{\q} + @code{\&} @code{&} The matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\\&} @code{\&} A literal @samp{&} + @code{\\\\&} @code{\\&} A literal @samp{\&} + @code{\\\\\&} @code{\\&} A literal @samp{\&} +@code{\\\\\\&} @code{\\\&} A literal @samp{\\&} + @code{\\q} @code{\q} A literal @samp{\q} @end display @end ifnotdocbook @end ifnottex @@ -16902,86 +17031,19 @@ case of even numbers of backslashes entered at the lexical level.) The problem with the historical approach is that there is no way to get a literal @samp{\} followed by the matched text. -@c @cindex @command{awk} language, POSIX version -@cindex POSIX @command{awk}, functions and, @code{gsub()}/@code{sub()} -The 1992 POSIX standard attempted to fix this problem. That standard -says that @code{sub()} and @code{gsub()} look for either a @samp{\} or an @samp{&} -after the @samp{\}. If either one follows a @samp{\}, that character is -output literally. The interpretation of @samp{\} and @samp{&} then becomes -as shown in @ref{table-sub-posix-92}. - -@float Table,table-sub-posix-92 -@caption{1992 POSIX Rules for @code{sub()} and @code{gsub()} Escape Sequence Processing} -@c thanks to Karl Berry for formatting this table -@tex -\vbox{\bigskip -% We need more characters for escape and tab ... -\catcode`_ = 0 -\catcode`! = 4 -% ... since this table has lots of &'s and \'s, so we unspecialize them. -\catcode`\& = \other \catcode`\\ = \other -_halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr - You type!@code{sub()} sees!@code{sub()} generates_cr -_hrulefill!_hrulefill!_hrulefill_cr - @code{&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, then the matched text_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -} -_bigskip} -@end tex -@ifdocbook -@multitable @columnfractions .20 .20 .60 -@headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, then the matched text -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@end multitable -@end ifdocbook -@ifnottex -@ifnotdocbook -@display - You type @code{sub()} sees @code{sub()} generates - -------- ---------- --------------- - @code{&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\\&} @code{\\&} a literal @samp{\}, then the matched text -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} -@end display -@end ifnotdocbook -@end ifnottex -@end float - -@noindent -This appears to solve the problem. -Unfortunately, the phrasing of the standard is unusual. It -says, in effect, that @samp{\} turns off the special meaning of any -following character, but for anything other than @samp{\} and @samp{&}, -such special meaning is undefined. This wording leads to two problems: - -@itemize @value{BULLET} -@item -Backslashes must now be doubled in the @var{replacement} string, breaking -historical @command{awk} programs. +Several editions of the POSIX standard attempted to fix this problem +but weren't successful. The details are irrelevant at this point in time. -@item -To make sure that an @command{awk} program is portable, @emph{every} character -in the @var{replacement} string must be preceded with a -backslash.@footnote{This consequence was certainly unintended.} -@c I can say that, 'cause I was involved in making this change -@end itemize - -Because of the problems just listed, -in 1996, the @command{gawk} maintainer submitted +At one point, the @command{gawk} maintainer submitted proposed text for a revised standard that reverts to rules that correspond more closely to the original existing practice. The proposed rules have special cases that make it possible -to produce a @samp{\} preceding the matched text. This is shown in +to produce a @samp{\} preceding the matched text. +This is shown in @ref{table-sub-proposed}. @float Table,table-sub-proposed -@caption{Proposed Rules For @code{sub()} And Backslash} +@caption{GNU @command{awk} Rules For @code{sub()} And Backslash} @tex \vbox{\bigskip % We need more characters for escape and tab ... @@ -16992,10 +17054,10 @@ to produce a @samp{\} preceding the matched text. This is shown in _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, followed by the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr +@code{\\\\&}! @code{\\&}!A literal @samp{\}, followed by the matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr @code{\\\\}! @code{\\}!@code{\\}_cr } _bigskip} @@ -17003,10 +17065,10 @@ _bigskip} @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, followed by the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, followed by the matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @item @code{\\\\} @tab @code{\\} @tab @code{\\} @end multitable @end ifdocbook @@ -17015,10 +17077,10 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\\\&} @code{\\&} a literal @samp{\}, followed by the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\q} @code{\q} a literal @samp{\q} +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\\\&} @code{\\&} A literal @samp{\}, followed by the matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\q} @code{\q} A literal @samp{\q} @code{\\\\} @code{\\} @code{\\} @end display @end ifnotdocbook @@ -17031,13 +17093,13 @@ there was only one. However, as in the historical case, any @samp{\} that is not part of one of these three sequences is not special and appears in the output literally. -@command{gawk} 3.0 and 3.1 follow these proposed POSIX rules for @code{sub()} and -@code{gsub()}. -@c As much as we think it's a lousy idea. You win some, you lose some. Sigh. -The POSIX standard took much longer to be revised than was expected in 1996. -The 2001 standard does not follow the above rules. Instead, the rules -there are somewhat simpler. The results are similar except for one case. +@command{gawk} 3.0 and 3.1 follow these rules for @code{sub()} and +@code{gsub()}. The POSIX standard took much longer to be revised than +was expected. In addition, the @command{gawk} maintainer's proposal was +lost during the standardization process. The final rules are +somewhat simpler. The results are similar except for one case. +@cindex POSIX @command{awk}, functions and, @code{gsub()}/@code{sub()} The POSIX rules state that @samp{\&} in the replacement string produces a literal @samp{&}, @samp{\\} produces a literal @samp{\}, and @samp{\} followed by anything else is not special; the @samp{\} is placed straight into the output. @@ -17055,10 +17117,10 @@ These rules are presented in @ref{table-posix-sub}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{sub()} sees!@code{sub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr -@code{\\\\&}! @code{\\&}!a literal @samp{\}, followed by the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\q}! @code{\q}!a literal @samp{\q}_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr +@code{\\\\&}! @code{\\&}!A literal @samp{\}, followed by the matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\q}! @code{\q}!A literal @samp{\q}_cr @code{\\\\}! @code{\\}!@code{\}_cr } _bigskip} @@ -17066,10 +17128,10 @@ _bigskip} @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{sub()} sees @tab @code{sub()} generates -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, followed by the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{\q} +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, followed by the matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{\q} @item @code{\\\\} @tab @code{\\} @tab @code{\} @end multitable @end ifdocbook @@ -17078,10 +17140,10 @@ _bigskip} @display You type @code{sub()} sees @code{sub()} generates -------- ---------- --------------- -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\\\&} @code{\\&} a literal @samp{\}, followed by the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\q} @code{\q} a literal @samp{\q} +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\\\&} @code{\\&} A literal @samp{\}, followed by the matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\q} @code{\q} A literal @samp{\q} @code{\\\\} @code{\\} @code{\} @end display @end ifnotdocbook @@ -17093,7 +17155,7 @@ is seen as @samp{\\} and produces @samp{\} instead of @samp{\\}. Starting with @value{PVERSION} 3.1.4, @command{gawk} followed the POSIX rules when @option{--posix} is specified (@pxref{Options}). Otherwise, -it continued to follow the 1996 proposed rules, since +it continued to follow the proposed rules, since that had been its behavior for many years. When @value{PVERSION} 4.0.0 was released, the @command{gawk} maintainer @@ -17124,24 +17186,24 @@ as shown in @ref{table-gensub-escapes}. _halign{_hfil#!_qquad_hfil#!_qquad#_hfil_cr You type!@code{gensub()} sees!@code{gensub()} generates_cr _hrulefill!_hrulefill!_hrulefill_cr - @code{&}! @code{&}!the matched text_cr - @code{\\&}! @code{\&}!a literal @samp{&}_cr - @code{\\\\}! @code{\\}!a literal @samp{\}_cr - @code{\\\\&}! @code{\\&}!a literal @samp{\}, then the matched text_cr -@code{\\\\\\&}! @code{\\\&}!a literal @samp{\&}_cr - @code{\\q}! @code{\q}!a literal @samp{q}_cr + @code{&}! @code{&}!The matched text_cr + @code{\\&}! @code{\&}!A literal @samp{&}_cr + @code{\\\\}! @code{\\}!A literal @samp{\}_cr + @code{\\\\&}! @code{\\&}!A literal @samp{\}, then the matched text_cr +@code{\\\\\\&}! @code{\\\&}!A literal @samp{\&}_cr + @code{\\q}! @code{\q}!A literal @samp{q}_cr } _bigskip} @end tex @ifdocbook @multitable @columnfractions .20 .20 .60 @headitem You type @tab @code{gensub()} sees @tab @code{gensub()} generates -@item @code{&} @tab @code{&} @tab the matched text -@item @code{\\&} @tab @code{\&} @tab a literal @samp{&} -@item @code{\\\\} @tab @code{\\} @tab a literal @samp{\} -@item @code{\\\\&} @tab @code{\\&} @tab a literal @samp{\}, then the matched text -@item @code{\\\\\\&} @tab @code{\\\&} @tab a literal @samp{\&} -@item @code{\\q} @tab @code{\q} @tab a literal @samp{q} +@item @code{&} @tab @code{&} @tab The matched text +@item @code{\\&} @tab @code{\&} @tab A literal @samp{&} +@item @code{\\\\} @tab @code{\\} @tab A literal @samp{\} +@item @code{\\\\&} @tab @code{\\&} @tab A literal @samp{\}, then the matched text +@item @code{\\\\\\&} @tab @code{\\\&} @tab A literal @samp{\&} +@item @code{\\q} @tab @code{\q} @tab A literal @samp{q} @end multitable @end ifdocbook @ifnottex @@ -17149,12 +17211,12 @@ _bigskip} @display You type @code{gensub()} sees @code{gensub()} generates -------- ------------- ------------------ - @code{&} @code{&} the matched text - @code{\\&} @code{\&} a literal @samp{&} - @code{\\\\} @code{\\} a literal @samp{\} - @code{\\\\&} @code{\\&} a literal @samp{\}, then the matched text -@code{\\\\\\&} @code{\\\&} a literal @samp{\&} - @code{\\q} @code{\q} a literal @samp{q} + @code{&} @code{&} The matched text + @code{\\&} @code{\&} A literal @samp{&} + @code{\\\\} @code{\\} A literal @samp{\} + @code{\\\\&} @code{\\&} A literal @samp{\}, then the matched text +@code{\\\\\\&} @code{\\\&} A literal @samp{\&} + @code{\\q} @code{\q} A literal @samp{q} @end display @end ifnotdocbook @end ifnottex @@ -17236,7 +17298,7 @@ buffers its output and the @code{fflush()} function forces @cindex extensions, common@comma{} @code{fflush()} function @cindex Brian Kernighan's @command{awk} -@code{fflush()} was added to Brian Kernighan's @command{awk} in +@code{fflush()} was added to BWK @command{awk} in April of 1992. For two decades, it was not part of the POSIX standard. As of December, 2012, it was accepted for inclusion into the POSIX standard. @@ -18225,6 +18287,12 @@ them, i.e., to tell @command{awk} what they should do. @node Definition Syntax @subsection Function Definition Syntax +@quotation +It's entirely fair to say that the @command{awk} syntax for local +variable definitions is appallingly awful. +@author Brian Kernighan +@end quotation + @c STARTOFRANGE fdef @cindex functions, defining Definitions of functions can appear anywhere between the rules of an @@ -18264,7 +18332,7 @@ have a parameter with the same name as the function itself. In addition, according to the POSIX standard, function parameters cannot have the same name as one of the special built-in variables (@pxref{Built-in Variables}). Not all versions of @command{awk} enforce -this restriction.) +this restriction. Local variables act like the empty string if referenced where a string value is required, and like zero if referenced where a numeric value @@ -18394,7 +18462,8 @@ this program, using our function to format the results, prints: 21.2 @end example -This function deletes all the elements in an array: +This function deletes all the elements in an array (recall that the +extra whitespace signifies the start of the local variable list): @example function delarray(a, i) @@ -18417,17 +18486,18 @@ addition to the POSIX standard.) The following is an example of a recursive function. It takes a string as an input parameter and returns the string in backwards order. Recursive functions must always have a test that stops the recursion. -In this case, the recursion terminates when the starting position -is zero, i.e., when there are no more characters left in the string. +In this case, the recursion terminates when the input string is +already empty. +@c 8/2014: Thanks to Mike Brennan for the improved formulation @cindex @code{rev()} user-defined function @example -function rev(str, start) +function rev(str) @{ - if (start == 0) + if (str == "") return "" - return (substr(str, start, 1) rev(str, start - 1)) + return (rev(substr(str, 2)) substr(str, 1, 1)) @} @end example @@ -18436,7 +18506,7 @@ this way: @example $ @kbd{echo "Don't Panic!" |} -> @kbd{gawk --source '@{ print rev($0, length($0)) @}' -f rev.awk} +> @kbd{gawk -e '@{ print rev($0) @}' -f rev.awk} @print{} !cinaP t'noD @end example @@ -18721,7 +18791,7 @@ BEGIN @{ @noindent prints @samp{a[1] = 1, a[2] = two, a[3] = 3}, because -@code{changeit} stores @code{"two"} in the second element of @code{a}. +@code{changeit()} stores @code{"two"} in the second element of @code{a}. @end quotation @cindex undefined functions @@ -18897,7 +18967,7 @@ being aware of them. @cindex pointers to functions @cindex differences in @command{awk} and @command{gawk}, indirect function calls -This section describes a @command{gawk}-specific extension. +This section describes an advanced, @command{gawk}-specific extension. Often, you may wish to defer the choice of function to call until runtime. For example, you may have different kinds of records, each of which @@ -18943,8 +19013,11 @@ To process the data, you might write initially: @noindent This style of programming works, but can be awkward. With @dfn{indirect} function calls, you tell @command{gawk} to use the @emph{value} of a -variable as the name of the function to call. +variable as the @emph{name} of the function to call. +@cindex @code{@@}-notation for indirect function calls +@cindex indirect function calls, @code{@@}-notation +@cindex function calls, indirect, @code{@@}-notation for The syntax is similar to that of a regular function call: an identifier immediately followed by a left parenthesis, any arguments, and then a closing right parenthesis, with the addition of a leading @samp{@@} @@ -19002,7 +19075,6 @@ Otherwise they perform the expected computations and are not unusual. @example @c file eg/prog/indirectcall.awk # For each record, print the class name and the requested statistics - @{ class_name = $1 gsub(/_/, " ", class_name) # Replace _ with spaces @@ -19231,10 +19303,12 @@ $ @kbd{gawk -f quicksort.awk -f indirectcall.awk class_data2} Remember that you must supply a leading @samp{@@} in front of an indirect function call. -Unfortunately, indirect function calls cannot be used with the built-in functions. However, -you can generally write ``wrapper'' functions which call the built-in ones, and those can -be called indirectly. (Other than, perhaps, the mathematical functions, there is not a lot -of reason to try to call the built-in functions indirectly.) +Starting with @value{PVERSION} 4.1.2 of @command{gawk}, indirect function +calls may also be used with built-in functions and with extension functions +(@pxref{Dynamic Extensions}). The only thing you cannot do is pass a regular +expression constant to a built-in function through an indirect function +call.@footnote{This may change in a future version; recheck the documentation that +comes with your version of @command{gawk} to see if it has.} @command{gawk} does its best to make indirect function calls efficient. For example, in the following case: @@ -19245,7 +19319,7 @@ for (i = 1; i <= n; i++) @end example @noindent -@code{gawk} will look up the actual function to call only once. +@code{gawk} looks up the actual function to call only once. @node Functions Summary @section Summary @@ -19285,6 +19359,8 @@ from the real parameters by extra whitespace. User-defined functions may call other user-defined (and built-in) functions and may call themselves recursively. Function parameters ``hide'' any global variables of the same names. +You cannot use the name of a reserved variable (such as @code{ARGC}) +as the name of a parameter in user-defined functions. @item Scalar values are passed to user-defined functions by value. Array @@ -19303,7 +19379,7 @@ either scalar or array. @item @command{gawk} provides indirect function calls using a special syntax. -By setting a variable to the name of a user-defined function, you can +By setting a variable to the name of a function, you can determine at runtime what function will be called at that point in the program. This is equivalent to function pointers in C and C++. @@ -19338,7 +19414,7 @@ It contains the following chapters: @c STARTOFRANGE fudlib @cindex functions, user-defined, library of -@ref{User-defined}, describes how to write +@DBREF{User-defined} describes how to write your own @command{awk} functions. Writing functions is important, because it allows you to encapsulate algorithms and program tasks in a single place. It simplifies programming, making program development more @@ -19362,7 +19438,7 @@ of good programs leads to better writing. In fact, they felt this idea was so important that they placed this statement on the cover of their book. Because we believe strongly that their statement is correct, this @value{CHAPTER} and @ref{Sample -Programs}, provide a good-sized body of code for you to read, and we hope, +Programs}, provide a good-sized body of code for you to read and, we hope, to learn from. This @value{CHAPTER} presents a library of useful @command{awk} functions. @@ -19371,7 +19447,7 @@ use these functions. The functions are presented here in a progression from simple to complex. @cindex Texinfo -@ref{Extract Program}, +@DBREF{Extract Program} presents a program that you can use to extract the source code for these example library functions and programs from the Texinfo source for this @value{DOCUMENT}. @@ -19435,7 +19511,7 @@ comparisons use only lowercase letters. * Group Functions:: Functions for getting group information. * Walking Arrays:: A function to walk arrays of arrays. * Library Functions Summary:: Summary of library functions. -* Library exercises:: Exercises. +* Library Exercises:: Exercises. @end menu @node Library Names @@ -19522,7 +19598,7 @@ A different convention, common in the Tcl community, is to use a single associative array to hold the values needed by the library function(s), or ``package.'' This significantly decreases the number of actual global names in use. For example, the functions described in -@ref{Passwd Functions}, +@DBREF{Passwd Functions} might have used array elements @code{@w{PW_data["inited"]}}, @code{@w{PW_data["total"]}}, @code{@w{PW_data["count"]}}, and @code{@w{PW_data["awklib"]}}, instead of @code{@w{_pw_inited}}, @code{@w{_pw_awklib}}, @code{@w{_pw_total}}, @@ -19583,8 +19659,9 @@ function mystrtonum(str, ret, n, i, k, c) ret = 0 for (i = 1; i <= n; i++) @{ c = substr(str, i, 1) - if ((k = index("01234567", c)) > 0) - k-- # adjust for 1-basing in awk + # index() returns 0 if c not in string, + # includes c == "0" + k = index("1234567", c) ret = ret * 8 + k @} @@ -19596,6 +19673,8 @@ function mystrtonum(str, ret, n, i, k, c) for (i = 1; i <= n; i++) @{ c = substr(str, i, 1) c = tolower(c) + # index() returns 0 if c not in string, + # includes c == "0" k = index("123456789abcdef", c) ret = ret * 16 + k @@ -19997,8 +20076,7 @@ function chr(c) @c endfile #### test code #### -# BEGIN \ -# @{ +# BEGIN @{ # for (;;) @{ # printf("enter a character: ") # if (getline var <= 0) @@ -20083,7 +20161,7 @@ more difficult than they really need to be.} @cindex timestamps, formatted @cindex time, managing The @code{systime()} and @code{strftime()} functions described in -@ref{Time Functions}, +@DBREF{Time Functions} provide the minimum functionality necessary for dealing with the time of day in human readable form. While @code{strftime()} is extensive, the control formats are not necessarily easy to remember or intuitively obvious when @@ -20169,7 +20247,7 @@ function getlocaltime(time, ret, now, i) The string indices are easier to use and read than the various formats required by @code{strftime()}. The @code{alarm} program presented in -@ref{Alarm Program}, +@DBREF{Alarm Program} uses this function. A more general design for the @code{getlocaltime()} function would have allowed the user to supply an optional timestamp value to use instead @@ -20372,7 +20450,7 @@ END @{ endfile(_filename_) @} @c endfile @end example -@ref{Wc Program}, +@DBREF{Wc Program} shows how this library function can be used and how it simplifies writing the main program. @@ -20843,8 +20921,7 @@ it is not an option, and it ends option processing. Continuing on: i = index(options, thisopt) if (i == 0) @{ if (Opterr) - printf("%c -- invalid option\n", - thisopt) > "/dev/stderr" + printf("%c -- invalid option\n", thisopt) > "/dev/stderr" if (_opti >= length(argv[Optind])) @{ Optind++ _opti = 0 @@ -21347,7 +21424,7 @@ once. If you are worried about squeezing every last cycle out of your this is not necessary, since most @command{awk} programs are I/O-bound, and such a change would clutter up the code. -The @command{id} program in @ref{Id Program}, +The @command{id} program in @DBREF{Id Program} uses these functions. @c ENDOFRANGE libfudata @c ENDOFRANGE flibudata @@ -21373,7 +21450,7 @@ uses these functions. @cindex group file @cindex files, group Much of the discussion presented in -@ref{Passwd Functions}, +@DBREF{Passwd Functions} applies to the group database as well. Although there has traditionally been a well-known file (@file{/etc/group}) in a well-known format, the POSIX standard only provides a set of C library routines @@ -21526,8 +21603,7 @@ There are several, modeled after the C library functions of the same names: @c line break on _gr_init for smallbook @c file eg/lib/groupawk.in -BEGIN \ -@{ +BEGIN @{ # Change to suit your system _gr_awklib = "/usr/local/libexec/awk/" @} @@ -21713,13 +21789,13 @@ Most of the work is in scanning the database and building the various associative arrays. The functions that the user calls are themselves very simple, relying on @command{awk}'s associative arrays to do work. -The @command{id} program in @ref{Id Program}, +The @command{id} program in @DBREF{Id Program} uses these functions. @node Walking Arrays @section Traversing Arrays of Arrays -@ref{Arrays of Arrays}, described how @command{gawk} +@DBREF{Arrays of Arrays} described how @command{gawk} provides arrays of arrays. In particular, any element of an array may be either a scalar, or another array. The @code{isarray()} function (@pxref{Type Functions}) @@ -21825,7 +21901,8 @@ A simple function to traverse an array of arrays to any depth. @end itemize -@node Library exercises +@c EXCLUDE START +@node Library Exercises @section Exercises @enumerate @@ -21873,7 +21950,7 @@ As a related challenge, revise that code to handle the case where an intervening value in @code{ARGV} is a variable assignment. @item -@ref{Walking Arrays}, presented a function that walked a multidimensional +@DBREF{Walking Arrays} presented a function that walked a multidimensional array to print it out. However, walking an array and processing each element is a general-purpose operation. Generalize the @code{walk_array()} function by adding an additional parameter named @@ -21891,6 +21968,7 @@ Test your new version by printing the array; you should end up with output identical to that of the original version. @end enumerate +@c EXCLUDE END @c ENDOFRANGE flib @c ENDOFRANGE fudlib @@ -22104,8 +22182,7 @@ string: @example @c file eg/prog/cut.awk -BEGIN \ -@{ +BEGIN @{ FS = "\t" # default OFS = FS while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) @{ @@ -22580,8 +22657,7 @@ there are no matches, the exit status is one; otherwise it is zero: @example @c file eg/prog/egrep.awk -END \ -@{ +END @{ exit (total == 0) @} @c endfile @@ -22605,17 +22681,6 @@ function usage( e) The variable @code{e} is used so that the function fits nicely on the printed page. -@cindex @code{END} pattern, backslash continuation and -@cindex @code{\} (backslash), continuing lines and -@cindex backslash (@code{\}), continuing lines and -Just a note on programming style: you may have noticed that the @code{END} -rule uses backslash continuation, with the open brace on a line by -itself. This is so that it more closely resembles the way functions -are written. Many of the examples -in this @value{CHAPTER} -use this style. You can decide for yourself if you like writing -your @code{BEGIN} and @code{END} rules this way -or not. @c ENDOFRANGE regexps @c ENDOFRANGE sfregexp @c ENDOFRANGE fsregexp @@ -22682,8 +22747,7 @@ numbers: # egid=5(blat) groups=9(nine),2(two),1(one) @group -BEGIN \ -@{ +BEGIN @{ uid = PROCINFO["uid"] euid = PROCINFO["euid"] gid = PROCINFO["gid"] @@ -22900,6 +22964,12 @@ instead of doing it in an @code{END} rule. It also assumes that letters are contiguous in the character set, which isn't true for EBCDIC systems. +@ifset FOR_PRINT +You might want to consider how to eliminate the use of +@code{ord()} and @code{chr()}; this can be done in such a +way as to solve the EBCDIC issue as well. +@end ifset + @c ENDOFRANGE filspl @c ENDOFRANGE split @@ -22953,8 +23023,7 @@ Finally, @command{awk} is forced to read the standard input by setting @c endfile @end ignore @c file eg/prog/tee.awk -BEGIN \ -@{ +BEGIN @{ for (i = 1; i < ARGC; i++) copy[i] = ARGV[i] @@ -23016,8 +23085,7 @@ Finally, the @code{END} rule cleans up by closing all the output files: @example @c file eg/prog/tee.awk -END \ -@{ +END @{ for (i in copy) close(copy[i]) @} @@ -23134,8 +23202,7 @@ function usage( e) # -n skip n fields # +n skip n characters, skip fields first -BEGIN \ -@{ +BEGIN @{ count = 1 outputfile = "/dev/stdout" opts = "udc0:1:2:3:4:5:6:7:8:9:" @@ -23147,7 +23214,7 @@ BEGIN \ else if (c == "c") do_count++ else if (index("0123456789", c) != 0) @{ - # getopt requires args to options + # getopt() requires args to options # this messes us up for things like -5 if (Optarg ~ /^[[:digit:]]+$/) fcount = (c Optarg) + 0 @@ -23284,6 +23351,22 @@ END @{ @} @c endfile @end example + +@ifset FOR_PRINT +The logic for choosing which lines to print represents a @dfn{state +machine}, which is ``a device that can be in one of a set number of stable +conditions depending on its previous condition and on the present values +of its inputs.''@footnote{This is the definition returned from entering +@code{define: state machine} into Google.} +Brian Kernighan suggests that +``an alternative approach to state mechines is to just read +the input into an array, then use indexing. It's almost always +easier code, and for most inputs where you would use this, just +as fast.'' Consider how to rewrite the logic to follow this +suggestion. +@end ifset + + @c ENDOFRANGE prunt @c ENDOFRANGE tpul @c ENDOFRANGE uniq @@ -23654,8 +23737,7 @@ Here is the program: @c file eg/prog/alarm.awk # usage: alarm time [ "message" [ count [ delay ] ] ] -BEGIN \ -@{ +BEGIN @{ # Initial argument sanity checking usage1 = "usage: alarm time ['message' [count [delay]]]" usage2 = sprintf("\t(%s) time ::= hh:mm", ARGV[1]) @@ -23810,7 +23892,7 @@ of standard @command{awk}: dealing with individual characters is very painful, requiring repeated use of the @code{substr()}, @code{index()}, and @code{gsub()} built-in functions (@pxref{String Functions}).@footnote{This -program was written before @command{gawk} acquired the ability to +program was also written before @command{gawk} acquired the ability to split each character in a string into separate array elements.} There are two functions. The first, @code{stranslate()}, takes three arguments: @@ -23918,6 +24000,12 @@ An obvious improvement to this program would be to set up the @code{t_ar} array only once, in a @code{BEGIN} rule. However, this assumes that the ``from'' and ``to'' lists will never change throughout the lifetime of the program. + +Another obvious improvement is to enable the use of ranges, +such as @samp{a-z}, as allowed by the @command{tr} utility. +Look at the code for @file{cut.awk} (@pxref{Cut Program}) +for inspiration. + @c ENDOFRANGE chtra @c ENDOFRANGE tr @@ -24050,8 +24138,7 @@ function printpage( i, j) Count++ @} -END \ -@{ +END @{ printpage() @} @c endfile @@ -24702,7 +24789,7 @@ a shell variable that will be expanded. There are two cases: @enumerate a @item -Literal text, provided with @option{--source} or @option{--source=}. This +Literal text, provided with @option{-e} or @option{--source}. This text is just appended directly. @item @@ -25047,7 +25134,7 @@ The program should exit without reading any @value{DF}s. However, suppose that an included library file defines an @code{END} rule of its own. In this case, @command{gawk} will hang, reading standard input. In order to avoid this, @file{/dev/null} is explicitly added to the -command-line. Reading from @file{/dev/null} always returns an immediate +command line. Reading from @file{/dev/null} always returns an immediate end of file indication. @c Hmm. Add /dev/null if $# is 0? Still messes up ARGV. Sigh. @@ -25390,6 +25477,7 @@ mailing labels, and finding anagrams. @end itemize +@c EXCLUDE START @node Programs Exercises @section Exercises @@ -25413,17 +25501,27 @@ information is printed. Modify the @command{awk} version same way. @item -The @code{split.awk} program (@pxref{Split Program}) uses -the @code{chr()} and @code{ord()} functions to move through the -letters of the alphabet. -Modify the program to instead use only the @command{awk} -built-in functions, such as @code{index()} and @code{substr()}. - -@item The @code{split.awk} program (@pxref{Split Program}) assumes that letters are contiguous in the character set, which isn't true for EBCDIC systems. Fix this problem. +(Hint: Consider a different way to work through the alphabet, +without relying on @code{ord()} and @code{chr()}.) + +@item +In @file{uniq.awk} (@pxref{Uniq Program}, the +logic for choosing which lines to print represents a @dfn{state +machine}, which is ``a device that can be in one of a set number of stable +conditions depending on its previous condition and on the present values +of its inputs.''@footnote{This is the definition returned from entering +@code{define: state machine} into Google.} +Brian Kernighan suggests that +``an alternative approach to state mechines is to just read +the input into an array, then use indexing. It's almost always +easier code, and for most inputs where you would use this, just +as fast.'' Rewrite the logic to follow this +suggestion. + @item Why can't the @file{wc.awk} program (@pxref{Wc Program}) just @@ -25519,6 +25617,7 @@ Modify @file{anagram.awk} (@pxref{Anagram Program}), to avoid the use of the external @command{sort} utility. @end enumerate +@c EXCLUDE END @ifnotinfo @part @value{PART3}Moving Beyond Standard @command{awk} With @command{gawk} @@ -25700,7 +25799,7 @@ Often, though, it is desirable to be able to loop over the elements in a particular order that you, the programmer, choose. @command{gawk} lets you do this. -@ref{Controlling Scanning}, describes how you can assign special, +@DBREF{Controlling Scanning} describes how you can assign special, pre-defined values to @code{PROCINFO["sorted_in"]} in order to control the order in which @command{gawk} traverses an array during a @code{for} loop. @@ -26069,6 +26168,9 @@ Caveat Emptor. @node Two-way I/O @section Two-Way Communications with Another Process + +@c 8/2014. Neither Mike nor BWK saw this as relevant. Commenting it out. +@ignore @cindex Brennan, Michael @cindex programmers, attractiveness of @smallexample @@ -26098,6 +26200,7 @@ the scent of perl programmers. Mike Brennan @c brennan@@whidbey.com @end smallexample +@end ignore @cindex advanced features, processes@comma{} communicating with @cindex processes, two-way communications with @@ -26124,7 +26227,10 @@ system("rm " tempfile) This works, but not elegantly. Among other things, it requires that the program be run in a directory that cannot be shared among users; for example, @file{/tmp} will not do, as another user might happen -to be using a temporary file with the same name. +to be using a temporary file with the same name.@footnote{Michael +Brennan suggests the use of @command{rand()} to generate unique +@value{FN}s. This is a valid point; nevertheless, temporary files +remain more difficult than two-way pipes.} @c 8/2014 @cindex coprocesses @cindex input/output, two-way @@ -26279,7 +26385,7 @@ You can think of this as just a @emph{very long} two-way pipeline to a coprocess. The way @command{gawk} decides that you want to use TCP/IP networking is by recognizing special @value{FN}s that begin with one of @samp{/inet/}, -@samp{/inet4/} or @samp{/inet6}. +@samp{/inet4/} or @samp{/inet6/}. The full syntax of the special @value{FN} is @file{/@var{net-type}/@var{protocol}/@var{local-port}/@var{remote-host}/@var{remote-port}}. @@ -26930,7 +27036,16 @@ and/or groups of characters sort in a given language. @cindex @code{LC_CTYPE} locale category @item LC_CTYPE Character-type information (alphabetic, digit, upper- or lowercase, and -so on). +so on) as well as character encoding. +@ignore +In June 2001 Bruno Haible wrote: +- Description of LC_CTYPE: It determines both + 1. character encoding, + 2. character type information. + (For example, in both KOI8-R and ISO-8859-5 the character type information + is the same - cyrillic letters could as 'alpha' - but the encoding is + different.) +@end ignore This information is accessed via the POSIX character classes in regular expressions, such as @code{/[[:alnum:]]/} @@ -26951,11 +27066,6 @@ use a comma every three decimal places and a period for the decimal point, while many Europeans do exactly the opposite: 1,234.56 versus 1.234,56.} -@cindex @code{LC_RESPONSE} locale category -@item LC_RESPONSE -Response information, such as how ``yes'' and ``no'' appear in the -local language, and possibly other information as well. - @cindex time, localization and @cindex dates, information related to@comma{} localization @cindex @code{LC_TIME} locale category @@ -27090,18 +27200,33 @@ printf(_"Number of users is %d\n", nusers) @item If you are creating strings dynamically, you can still translate them, using the @code{dcgettext()} -built-in function: +built-in function:@footnote{Thanks to Bruno Haible for this +example.} @example -message = nusers " users logged in" -message = dcgettext(message, "adminprog") -print message +if (groggy) + message = dcgettext("%d customers disturbing me\n", "adminprog") +else + message = dcgettext("enjoying %d customers\n", "adminprog") +printf(message, ncustomers) @end example Here, the call to @code{dcgettext()} supplies a different text domain (@code{"adminprog"}) in which to find the message, but it uses the default @code{"LC_MESSAGES"} category. +The previous example only works if @code{ncustomers} is greater than one. +This example would be better done with @code{dcngettext()}: + +@example +if (groggy) + message = dcngettext("%d customer disturbing me\n", "%d customers disturbing me\n", "adminprog") +else + message = dcngettext("enjoying %d customer\n", "enjoying %d customers\n", "adminprog") +printf(message, ncustomers) +@end example + + @cindex @code{LC_MESSAGES} locale category, @code{bindtextdomain()} function (@command{gawk}) @item During development, you might want to put the @file{.gmo} @@ -27181,6 +27306,9 @@ appear as the first argument to @code{dcgettext()} or as the first and second argument to @code{dcngettext()}.@footnote{The @command{xgettext} utility that comes with GNU @command{gettext} can handle @file{.awk} files.} +You should distribute the generated @file{.pot} file with +your @command{awk} program; translators will eventually use it +to provide you translations that you can also then distribute. @xref{I18N Example}, for the full list of steps to go through to create and test translations for @command{guide}. @@ -27471,8 +27599,7 @@ This file must be renamed and placed in the proper directory so that @command{gawk} can find it: @example -$ @kbd{msgfmt guide-mellow.po} -$ @kbd{mv messages en_US.UTF-8/LC_MESSAGES/guide.mo} +$ @kbd{msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo} @end example Finally, we run the program to test it: @@ -27739,7 +27866,7 @@ to debug command-line programs, only programs contained in files.) In our case, we invoke the debugger like this: @example -$ @kbd{gawk -D -f getopt.awk -f join.awk -f uniq.awk inputfile} +$ @kbd{gawk -D -f getopt.awk -f join.awk -f uniq.awk -1 inputfile} @end example @noindent @@ -27801,7 +27928,7 @@ the breakpoint, use the @code{b} (breakpoint) command: @example gawk> @kbd{b are_equal} -@print{} Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 64 +@print{} Breakpoint 1 set at file `awklib/eg/prog/uniq.awk', line 63 @end example The debugger tells us the file and line number where the breakpoint is. @@ -27813,8 +27940,8 @@ gawk> @kbd{r} @print{} Starting program: @print{} Stopping in Rule ... @print{} Breakpoint 1, are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':64 -@print{} 64 if (fcount == 0 && charcount == 0) + at `awklib/eg/prog/uniq.awk':63 +@print{} 63 if (fcount == 0 && charcount == 0) gawk> @end example @@ -27826,12 +27953,12 @@ listing of the current stack frames: @example gawk> @kbd{bt} @print{} #0 are_equal(n, m, clast, cline, alast, aline) - at `awklib/eg/prog/uniq.awk':69 -@print{} #1 in main() at `awklib/eg/prog/uniq.awk':89 + at `awklib/eg/prog/uniq.awk':68 +@print{} #1 in main() at `awklib/eg/prog/uniq.awk':88 @end example This tells us that @code{are_equal()} was called by the main program at -line 89 of @file{uniq.awk}. (This is not a big surprise, since this +line 88 of @file{uniq.awk}. (This is not a big surprise, since this is the only call to @code{are_equal()} in the program, but in more complex programs, knowing who called a function and with what parameters can be the key to finding the source of the problem.) @@ -27855,7 +27982,7 @@ A more useful variable to display might be the current record: @example gawk> @kbd{p $0} -@print{} $0 = string ("gawk is a wonderful program!") +@print{} $0 = "gawk is a wonderful program!" @end example @noindent @@ -27864,7 +27991,7 @@ our test input above. Let's look at @code{NR}: @example gawk> @kbd{p NR} -@print{} NR = number (2) +@print{} NR = 2 @end example @noindent @@ -27883,7 +28010,7 @@ OK, let's just check that that rule worked correctly: @example gawk> @kbd{p last} -@print{} last = string ("awk is a wonderful program!") +@print{} last = "awk is a wonderful program!" @end example Everything we have done so far has verified that the program has worked as @@ -27894,13 +28021,13 @@ be inside this function. To investigate further, we must begin @example gawk> @kbd{n} -@print{} 67 if (fcount > 0) @{ +@print{} 66 if (fcount > 0) @{ @end example -This tells us that @command{gawk} is now ready to execute line 67, which +This tells us that @command{gawk} is now ready to execute line 66, which decides whether to give the lines the special ``field skipping'' treatment -indicated by the @option{-f} command-line option. (Notice that we skipped -from where we were before at line 64 to here, since the condition in line 64 +indicated by the @option{-1} command-line option. (Notice that we skipped +from where we were before at line 63 to here, since the condition in line 63 @samp{if (fcount == 0 && charcount == 0)} was false.) Continuing to step, we now get to the splitting of the current and @@ -27908,9 +28035,9 @@ last records: @example gawk> @kbd{n} -@print{} 68 n = split(last, alast) +@print{} 67 n = split(last, alast) gawk> @kbd{n} -@print{} 69 m = split($0, aline) +@print{} 68 m = split($0, aline) @end example At this point, we should be curious to see what our records were split @@ -27918,10 +28045,10 @@ into, so we try to look: @example gawk> @kbd{p n m alast aline} -@print{} n = number (5) -@print{} m = number (5) +@print{} n = 5 +@print{} m = untyped variable @print{} alast = array, 5 elements -@print{} aline = array, 5 elements +@print{} aline = untyped variable @end example @noindent @@ -27929,7 +28056,9 @@ gawk> @kbd{p n m alast aline} @command{awk}'s @code{print} statement.) This is kind of disappointing, though. All we found out is that there -are five elements in each of our arrays. Useful enough (we now know that +are five elements in @code{alast}; @code{m} and @code{aline} don't have +values yet since we are at line 68 but haven't executed it yet. +This information is useful enough (we now know that none of the words were accidentally left out), but what if we want to see inside the array? @@ -27945,7 +28074,7 @@ Oops! @example gawk> @kbd{p alast[1]} -@print{} alast["1"] = string ("awk") +@print{} alast["1"] = "awk" @end example This would be kind of slow for a 100-member array, though, so @@ -27954,11 +28083,11 @@ not to be mentioned): @example gawk> @kbd{p @@alast} -@print{} alast["1"] = string ("awk") -@print{} alast["2"] = string ("is") -@print{} alast["3"] = string ("a") -@print{} alast["4"] = string ("wonderful") -@print{} alast["5"] = string ("program!") +@print{} alast["1"] = "awk" +@print{} alast["2"] = "is" +@print{} alast["3"] = "a" +@print{} alast["4"] = "wonderful" +@print{} alast["5"] = "program!" @end example It looks like we got this far OK. Let's take another step @@ -27966,9 +28095,9 @@ or two: @example gawk> @kbd{n} -@print{} 70 clast = join(alast, fcount, n) +@print{} 69 clast = join(alast, fcount, n) gawk> @kbd{n} -@print{} 71 cline = join(aline, fcount, m) +@print{} 70 cline = join(aline, fcount, m) @end example Well, here we are at our error (sorry to spoil the suspense). What we @@ -27978,8 +28107,8 @@ this would work. Let's look at what we've got: @example gawk> @kbd{p cline clast} -@print{} cline = string ("gawk is a wonderful program!") -@print{} clast = string ("awk is a wonderful program!") +@print{} cline = "gawk is a wonderful program!" +@print{} clast = "awk is a wonderful program!" @end example Hey, those look pretty familiar! They're just our original, unaltered, @@ -28826,7 +28955,9 @@ responds @samp{syntax error}. When you do figure out what your mistake was, though, you'll feel like a real guru. @item -If you perused the dump of opcodes in @ref{Miscellaneous Debugger Commands}, +@c NOTE: no comma after the ref{} on purpose, due to following +@c parenthetical remark. +If you perused the dump of opcodes in @ref{Miscellaneous Debugger Commands} (or if you are already familiar with @command{gawk} internals), you will realize that much of the internal manipulation of data in @command{gawk}, as in many interpreters, is done on a stack. @@ -28874,7 +29005,7 @@ similarly to the GNU Debugger, GDB. @item Debuggers let you step through your program one statement at a time, examine and change variable and array values, and do a number of other -things that let understand what your program is actually doing (as +things that let you understand what your program is actually doing (as opposed to what it is supposed to do). @item @@ -28912,6 +29043,12 @@ arbitrary precision integers, and concludes with a description of some points where @command{gawk} and the POSIX standard are not quite in agreement. +@quotation NOTE +Most users of @command{gawk} can safely skip this chapter. +But if you want to do scientific calculations with @command{gawk}, +this is the place to be. +@end quotation + @menu * Computer Arithmetic:: A quick intro to computer math. * Math Definitions:: Defining terms used. @@ -29031,8 +29168,23 @@ A special value representing infinity. Operations involving another number and infinity produce infinity. @item NaN -``Not A Number.'' A special value indicating a result that can't -happen in real math, but that can happen in floating-point computations. +``Not A Number.''@footnote{Thanks +to Michael Brennan for this description, which I have paraphrased, and +for the examples}. +A special value that results from attempting a +calculation that has no answer as a real number. In such a case, +programs can either receive a floating-point exception, or get @code{NaN} +back as the result. The IEEE 754 standard recommends that systems return +@code{NaN}. Some examples: + +@table @code +@item sqrt(-1) +This makes sense in the range of complex numbers, but not in the +range of real numbers, so the result is @code{NaN}. + +@item log(-8) +@minus{}8 is out of the domain of @code{log()}, so the result is @code{NaN}. +@end table @item Normalized How the significand (see later in this list) is usually stored. The @@ -29139,8 +29291,8 @@ array to provide information about the MPFR and GMP libraries The MPFR library provides precise control over precisions and rounding modes, and gives correctly rounded, reproducible, platform-independent -results. With either of the command-line options @option{--bignum} or -@option{-M}, all floating-point arithmetic operators and numeric functions +results. With the @option{-M} command-line option, +all floating-point arithmetic operators and numeric functions can yield results to any desired precision level supported by MPFR. Two built-in variables, @code{PREC} and @code{ROUNDMODE}, @@ -29154,7 +29306,7 @@ to follow. @quotation Math class is tough! -@author Late 1980's Barbie +@author Teen Talk Barbie, July 1992 @end quotation This @value{SECTION} provides a high level overview of the issues @@ -29450,7 +29602,7 @@ internally as a MPFR number. Changing the precision using @code{PREC} in the program text does @emph{not} change the precision of a constant. If you need to represent a floating-point constant at a higher precision -than the default and cannot use a command line assignment to @code{PREC}, +than the default and cannot use a command-line assignment to @code{PREC}, you should either specify the constant as a string, or as a rational number, whenever possible. The following example illustrates the differences among various ways to print a floating-point constant: @@ -29566,7 +29718,7 @@ output when you change the rounding mode to be sure. @cindex integers, arbitrary precision @cindex arbitrary precision integers -When given one of the options @option{--bignum} or @option{-M}, +When given the @option{-M} option, @command{gawk} performs all integer arithmetic using GMP arbitrary precision integers. Any number that looks like an integer in a source or @value{DF} is stored as an arbitrary precision integer. The size @@ -29819,7 +29971,7 @@ values. The default for @command{awk} is to use double-precision floating-point values. @item -In the 1980's, Barbie mistakenly said ``Math class is tough!'' +In the early 1990's, Barbie mistakenly said ``Math class is tough!'' While math isn't tough, floating-point arithmetic isn't the same as pencil and paper math, and care must be taken: @@ -29847,12 +29999,12 @@ Often, increasing the accuracy and then rounding to the desired number of digits produces reasonable results. @item -Use either @option{-M} or @option{--bignum} to enable MPFR +Use @option{-M} (or @option{--bignum}) to enable MPFR arithmetic. Use @code{PREC} to set the precision in bits, and @code{ROUNDMODE} to set the IEEE 754 rounding mode. @item -With @option{-M} or @option{--bignum}, @command{gawk} performs +With @option{-M}, @command{gawk} performs arbitrary precision integer arithmetic using the GMP library. This is faster and more space efficient than using MPFR for the same calculations. @@ -30084,7 +30236,7 @@ Some other bits and pieces: @itemize @value{BULLET} @item The API provides access to @command{gawk}'s @code{do_@var{xxx}} values, -reflecting command line options, like @code{do_lint}, @code{do_profiling} +reflecting command-line options, like @code{do_lint}, @code{do_profiling} and so on (@pxref{Extension API Variables}). These are informational: an extension cannot affect their values inside @command{gawk}. In addition, attempting to assign to them @@ -30235,7 +30387,7 @@ does not support this keyword, you should either place @file{config.h} file in your extensions. @item -All pointers filled in by @command{gawk} are to memory +All pointers filled in by @command{gawk} point to memory managed by @command{gawk} and should be treated by the extension as read-only. Memory for @emph{all} strings passed into @command{gawk} from the extension @emph{must} come from calling the API-provided function @@ -30769,8 +30921,8 @@ empty string (@code{""}). The @code{func} pointer is the address of a An @dfn{exit callback} function is a function that @command{gawk} calls before it exits. Such functions are useful if you have general ``cleanup'' tasks -that should be performed in your extension (such as closing data -base connections or other resource deallocations). +that should be performed in your extension (such as closing database +connections or other resource deallocations). You can register such a function with @command{gawk} using the following function. @@ -33848,6 +34000,7 @@ should be the place to do so. @end itemize +@c EXCLUDE START @node Extension Exercises @section Exercises @@ -33870,6 +34023,7 @@ Write a wrapper script that provides an interface similar to @ref{Extension Sample Inplace}. @end enumerate +@c EXCLUDE END @ifnotinfo @part @value{PART4}Appendices @@ -34300,7 +34454,7 @@ Indirect function calls @item Directories on the command line produce a warning and are skipped -(@pxref{Command line directories}). +(@pxref{Command-line directories}). @end itemize @item @@ -34384,8 +34538,7 @@ functions for internationalization (@pxref{Programmer i18n}). @item -The @code{fflush()} function from Brian Kernighan's -version of @command{awk} +The @code{fflush()} function from BWK @command{awk} (@pxref{I/O Functions}). @item @@ -34449,7 +34602,7 @@ and the @option{--copyright}, @option{--debug}, @option{--dump-variables}, -@option{--execle}, +@option{--exec}, @option{--field-separator}, @option{--file}, @option{--gen-pot}, @@ -34530,6 +34683,10 @@ and the documentation for @command{gawk} @value{PVERSION} 4.1: Ultrix @end itemize +@item +@c FIXME: Verify the version here. +Support for MirBSD was removed at @command{gawk} @value{PVERSION} 4.2. + @end itemize @c XXX ADD MORE STUFF HERE @@ -34647,7 +34804,7 @@ The ability to delete all of an array at once with @samp{delete @var{array}} (@pxref{Delete}). @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -34705,12 +34862,12 @@ The @code{next file} statement became @code{nextfile} @item The @code{fflush()} function from -Brian Kernighan's @command{awk} +BWK @command{awk} (then at Bell Laboratories; @pxref{I/O Functions}). @item -New command line options: +New command-line options: @itemize @value{MINUS} @item @@ -34720,7 +34877,7 @@ the original Version 7 Unix version of @command{awk} (@pxref{V7/SVR3.1}). @item -The @option{-m} option from Brian Kernighan's @command{awk}. (He was +The @option{-m} option from BWK @command{awk}. (Brian was still at Bell Laboratories at the time.) This was later removed from both his @command{awk} and from @command{gawk}. @@ -34962,7 +35119,7 @@ An optional third argument to (@pxref{String Functions}). @item -The behavior of @code{fflush()} changed to match Brian Kernighan's @command{awk} +The behavior of @code{fflush()} changed to match BWK @command{awk} and for POSIX; now both @samp{fflush()} and @samp{fflush("")} flush all open output redirections (@pxref{I/O Functions}). @@ -35000,7 +35157,7 @@ Indirect function calls (@pxref{Switch Statement}). @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -35025,7 +35182,7 @@ All long options acquired corresponding short options, for use in @samp{#!} scri @item Directories named on the command line now produce a warning, not a fatal error, unless @option{--posix} or @option{--traditional} are used -(@pxref{Command line directories}). +(@pxref{Command-line directories}). @item The @command{gawk} internals were rewritten, bringing the @command{dgawk} @@ -35101,10 +35258,10 @@ Three new arrays: @item The three executables @command{gawk}, @command{pgawk}, and @command{dgawk}, were merged into -one, named just @command{gawk}. As a result the command line options changed. +one, named just @command{gawk}. As a result the command-line options changed. @item -Command line option changes +Command-line option changes (@pxref{Options}): @itemize @value{MINUS} @@ -36446,7 +36603,7 @@ The following changes the record separator to @code{"\r\n"} and sets binary mode on reads, but does not affect the mode on standard input: @example -gawk -v RS="\r\n" --source "BEGIN @{ BINMODE = 1 @}" @dots{} +gawk -v RS="\r\n" -e "BEGIN @{ BINMODE = 1 @}" @dots{} @end example @noindent @@ -37059,7 +37216,7 @@ since approximately 2003. @cindex source code, @command{pawk} @item @command{pawk} Nelson H.F.@: Beebe at the University of Utah has modified -Brian Kernighan's @command{awk} to provide timing and profiling information. +BWK @command{awk} to provide timing and profiling information. It is different from @command{gawk} with the @option{--profile} option. (@pxref{Profiling}), in that it uses CPU-based profiling, not line-count @@ -37122,8 +37279,7 @@ This is an embeddable @command{awk} interpreter derived from This is a Python module that claims to bring @command{awk}-like features to Python. See @uref{https://github.com/alecthomas/pawk} for more information. (This is not related to Nelson Beebe's -modified version of Brian Kernighan's @command{awk}, -described earlier.) +modified version of BWK @command{awk}, described earlier.) @item @w{QSE Awk} @cindex QSE Awk @@ -37262,7 +37418,7 @@ as well as any considerations you should bear in mind. @appendixsubsec Accessing The @command{gawk} Git Repository As @command{gawk} is Free Software, the source code is always available. -@ref{Gawk Distribution}, describes how to get and build the formal, +@DBREF{Gawk Distribution} describes how to get and build the formal, released versions of @command{gawk}. @cindex @command{git} utility @@ -38144,7 +38300,7 @@ compiled with @samp{-DDEBUG}. @item The source code for @command{gawk} is maintained in a publicly -accessable Git repository. Anyone may check it out and view the source. +accessible Git repository. Anyone may check it out and view the source. @item Contributions to @command{gawk} are welcome. Following the steps @@ -40482,13 +40638,14 @@ Consistency issues: Use "zeros" instead of "zeroes". Use "nonzero" not "non-zero". Use "runtime" not "run time" or "run-time". - Use "command-line" not "command line". + Use "command-line" as an adjective and "command line" as a noun. Use "online" not "on-line". Use "whitespace" not "white space". Use "Input/Output", not "input/output". Also "I/O", not "i/o". Use "lefthand"/"righthand", not "left-hand"/"right-hand". Use "workaround", not "work-around". Use "startup"/"cleanup", not "start-up"/"clean-up" + Use "filesystem", not "file system" Use @code{do}, and not @code{do}-@code{while}, except where actually discussing the do-while. Use "versus" in text and "vs." in index entries @@ -40503,8 +40660,6 @@ Consistency issues: The numbers zero through ten should be spelled out, except when talking about file descriptor numbers. > 10 and < 0, it's ok to use numbers. - In tables, put command-line options in @code, while in the text, - put them in @option. For most cases, do NOT put a comma before "and", "or" or "but". But exercise taste with this rule. Don't show the awk command with a program in quotes when it's @@ -241,6 +241,7 @@ static const char *const nodetypes[] = { "Node_func", "Node_ext_func", "Node_old_ext_func", + "Node_builtin_func", "Node_array_ref", "Node_array_tree", "Node_array_leaf", diff --git a/helpers/ChangeLog b/helpers/ChangeLog index c9121403..a5bbafb1 100644 --- a/helpers/ChangeLog +++ b/helpers/ChangeLog @@ -1,3 +1,7 @@ +2014-09-04 Arnold D. Robbins <arnold@skeeve.com> + + * chlistref.awk: New file. Finds @ref{} to non-chapters. + 2014-06-08 Arnold D. Robbins <arnold@skeeve.com> * testdfa.c: Minor improvements. diff --git a/helpers/chlistref.awk b/helpers/chlistref.awk new file mode 100644 index 00000000..49f63f59 --- /dev/null +++ b/helpers/chlistref.awk @@ -0,0 +1,31 @@ +BEGIN { + chapters["Getting Started"]++ + chapters["Invoking Gawk"]++ + chapters["Regexp"]++ + chapters["Reading Files"]++ + chapters["Printing"]++ + chapters["Expressions"]++ + chapters["Patterns and Actions"]++ + chapters["Arrays"]++ + chapters["Functions"]++ + chapters["Library Functions"]++ + chapters["Sample Programs"]++ + chapters["Advanced Features"]++ + chapters["Internationalization"]++ + chapters["Debugger"]++ + chapters["Arbitrary Precision Arithmetic"]++ + chapters["Dynamic Extensions"]++ + chapters["Language History"]++ + chapters["Installation"]++ + chapters["Notes"]++ + chapters["Basic Concepts"]++ + + Pattern = ".*@ref\\{([^}]+)\\},.*" +} + +$0 ~ Pattern { + ref = gensub(Pattern, "\\1", 1, $0) + if (! (ref in chapters)) + printf("%s:%d: %s\n", FILENAME, FNR, $0) +} + diff --git a/interpret.h b/interpret.h index 70cb214b..23ce0c1a 100644 --- a/interpret.h +++ b/interpret.h @@ -1038,10 +1038,44 @@ match_re: f = lookup(t1->stptr); } - if (f == NULL || f->type != Node_func) { - if (f->type == Node_ext_func || f->type == Node_old_ext_func) - fatal(_("cannot (yet) call extension functions indirectly")); - else + if (f == NULL) { + fatal(_("`%s' is not a function, so it cannot be called indirectly"), + t1->stptr); + } else if (f->type == Node_builtin_func) { + int arg_count = (pc + 1)->expr_count; + builtin_func_t the_func = lookup_builtin(t1->stptr); + + assert(the_func != NULL); + + /* call it */ + r = the_func(arg_count); + PUSH(r); + break; + } else if (f->type != Node_func) { + if ( f->type == Node_ext_func + || f->type == Node_old_ext_func) { + /* code copied from below, keep in sync */ + INSTRUCTION *bc; + char *fname = pc->func_name; + int arg_count = (pc + 1)->expr_count; + static INSTRUCTION npc[2]; + + npc[0] = *pc; + + bc = f->code_ptr; + assert(bc->opcode == Op_symbol); + if (f->type == Node_ext_func) + npc[0].opcode = Op_ext_builtin; /* self modifying code */ + else + npc[0].opcode = Op_old_ext_builtin; /* self modifying code */ + npc[0].extfunc = bc->extfunc; + npc[0].expr_count = arg_count; /* actual argument count */ + npc[1] = pc[1]; + npc[1].func_name = fname; /* name of the builtin */ + npc[1].expr_count = bc->expr_count; /* defined max # of arguments */ + ni = npc; + JUMPTO(ni); + } else fatal(_("function called indirectly through `%s' does not exist"), pc->func_name); } @@ -1065,6 +1099,7 @@ match_re: } if (f->type == Node_ext_func || f->type == Node_old_ext_func) { + /* keep in sync with indirect call code */ INSTRUCTION *bc; char *fname = pc->func_name; int arg_count = (pc + 1)->expr_count; @@ -33,6 +33,16 @@ #include <mcheck.h> #endif +#ifdef HAVE_LIBSIGSEGV +#include <sigsegv.h> +#else +typedef void *stackoverflow_context_t; +/* the argument to this macro is purposely not used */ +#define sigsegv_install_handler(catchsegv) signal(SIGSEGV, catchsig) +/* define as 0 rather than empty so that (void) cast on it works */ +#define stackoverflow_install_handler(catchstackoverflow, extra_stack, STACK_SIZE) 0 +#endif + #define DEFAULT_PROFILE "awkprof.out" /* where to put profile */ #define DEFAULT_VARFILE "awkvars.out" /* where to put vars */ #define DEFAULT_PREC 53 @@ -262,17 +272,6 @@ main(int argc, char **argv) */ gawk_mb_cur_max = MB_CUR_MAX; /* Without MBS_SUPPORT, gawk_mb_cur_max is 1. */ -#ifdef LIBC_IS_BORKED -{ - const char *env_lc; - - env_lc = getenv("LC_ALL"); - if (env_lc == NULL) - env_lc = getenv("LANG"); - if (env_lc != NULL && env_lc[1] == '\0' && tolower(env_lc[0]) == 'c') - gawk_mb_cur_max = 1; -} -#endif /* init the cache for checking bytes if they're characters */ init_btowc_cache(); @@ -705,6 +704,8 @@ out: if (do_intl) exit(EXIT_SUCCESS); + install_builtins(); + if (do_lint) shadow_funcs(); @@ -825,7 +826,7 @@ usage(int exitval, FILE *fp) fputs(_("\t-h\t\t\t--help\n"), fp); fputs(_("\t-i includefile\t\t--include=includefile\n"), fp); fputs(_("\t-l library\t\t--load=library\n"), fp); - fputs(_("\t-L [fatal]\t\t--lint[=fatal]\n"), fp); + fputs(_("\t-L[fatal|invalid]\t--lint[=fatal|invalid]\n"), fp); fputs(_("\t-M\t\t\t--bignum\n"), fp); fputs(_("\t-N\t\t\t--use-lc-numeric\n"), fp); fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp); @@ -557,9 +557,8 @@ parse_escape(const char **string_ptr) warning(_("no hex digits in `\\x' escape sequence")); return ('x'); } - i = j = 0; start = *string_ptr; - for (;; j++) { + for (i = j = 0; j < 2; j++) { /* do outside test to avoid multiple side effects */ c = *(*string_ptr)++; if (isxdigit(c)) { @@ -755,20 +755,28 @@ cleanup: ip = pc + 1; indent(ip->forloop_body->exec_count); fprintf(prof_fp, "%s (", op2str(pc->opcode)); - pprint(pc->nexti, ip->forloop_cond, true); - fprintf(prof_fp, "; "); - if (ip->forloop_cond->opcode == Op_no_op && - ip->forloop_cond->nexti == ip->forloop_body) + /* If empty for looop header, print it a little more nicely. */ + if ( pc->nexti->opcode == Op_no_op + && ip->forloop_cond == pc->nexti + && pc->target_continue->opcode == Op_jmp) { + fprintf(prof_fp, ";;"); + } else { + pprint(pc->nexti, ip->forloop_cond, true); fprintf(prof_fp, "; "); - else { - pprint(ip->forloop_cond, ip->forloop_body, true); - t1 = pp_pop(); - fprintf(prof_fp, "%s; ", t1->pp_str); - pp_free(t1); - } - pprint(pc->target_continue, pc->target_break, true); + if (ip->forloop_cond->opcode == Op_no_op && + ip->forloop_cond->nexti == ip->forloop_body) + fprintf(prof_fp, "; "); + else { + pprint(ip->forloop_cond, ip->forloop_body, true); + t1 = pp_pop(); + fprintf(prof_fp, "%s; ", t1->pp_str); + pp_free(t1); + } + + pprint(pc->target_continue, pc->target_break, true); + } fprintf(prof_fp, ") {\n"); indent_in(); pprint(ip->forloop_body->nexti, pc->target_continue, false); @@ -856,10 +856,6 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) #ifndef _LIBC char *codeset_name; #endif -#if defined(GAWK) && defined(LIBC_IS_BORKED) - /* Needed for brain damaged systems */ - extern int gawk_mb_cur_max; -#endif memset (dfa, '\0', sizeof (re_dfa_t)); @@ -881,11 +877,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); dfa->state_hash_mask = table_size - 1; -#if defined(GAWK) && defined(LIBC_IS_BORKED) - dfa->mb_cur_max = gawk_mb_cur_max; -#else dfa->mb_cur_max = MB_CUR_MAX; -#endif #ifdef _LIBC if (dfa->mb_cur_max == 6 && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) @@ -907,24 +899,9 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) codeset_name = strchr (codeset_name, '.') + 1; # endif - /* strcasecmp isn't a standard interface. brute force check */ -#ifndef GAWK if (strcasecmp (codeset_name, "UTF-8") == 0 || strcasecmp (codeset_name, "UTF8") == 0) dfa->is_utf8 = 1; -#else - if ( (codeset_name[0] == 'U' || codeset_name[0] == 'u') - && (codeset_name[1] == 'T' || codeset_name[1] == 't') - && (codeset_name[2] == 'F' || codeset_name[2] == 'f') - && (codeset_name[3] == '-' - ? codeset_name[4] == '8' && codeset_name[5] == '\0' - : codeset_name[3] == '8' && codeset_name[4] == '\0')) - dfa->is_utf8 = 1; -#if defined(GAWK) && defined(LIBC_IS_BORKED) - if (gawk_mb_cur_max == 1) - dfa->is_utf8 = 0; -#endif /* defined(GAWK) && defined(LIBC_IS_BORKED) */ -#endif /* We check exhaustively in the loop below if this charset is a superset of ASCII. */ @@ -2215,7 +2192,11 @@ parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, { branch = parse_branch (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && branch == NULL, 0)) - return NULL; + { + if (tree != NULL) + postorder (tree, free_tree, NULL); + return NULL; + } } else branch = NULL; @@ -2476,8 +2457,7 @@ parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { - bin_tree_t *dup_tree = parse_dup_op (tree, regexp, dfa, token, - syntax, err); + bin_tree_t *dup_tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); if (BE (*err != REG_NOERROR && dup_tree == NULL, 0)) { if (tree != NULL) @@ -2640,6 +2620,8 @@ parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, /* Duplicate ELEM before it is marked optional. */ elem = duplicate_tree (elem, dfa); + if (BE (elem == NULL, 0)) + goto parse_dup_op_espace; old_tree = tree; } else @@ -3136,8 +3118,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, if (BE (sbcset == NULL, 0)) #endif /* RE_ENABLE_I18N */ { -#ifdef RE_ENABLE_I18N re_free (sbcset); +#ifdef RE_ENABLE_I18N re_free (mbcset); #endif *err = REG_ESPACE; @@ -470,7 +470,7 @@ typedef struct #ifdef __USE_GNU /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ -extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); +extern reg_syntax_t re_set_syntax (reg_syntax_t syntax); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer @@ -480,14 +480,14 @@ extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); Note that the translate table must either have been initialised by `regcomp', with a malloc'ed value, or set to NULL before calling `regfree'. */ -extern const char *re_compile_pattern (const char *__pattern, size_t __length, - struct re_pattern_buffer *__buffer); +extern const char *re_compile_pattern (const char *pattern, size_t length, + struct re_pattern_buffer *buffer); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ -extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); +extern int re_compile_fastmap (struct re_pattern_buffer *buffer); /* Search in the string STRING (with length LENGTH) for the pattern @@ -495,30 +495,30 @@ extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ -extern int re_search (struct re_pattern_buffer *__buffer, const char *__cstring, - int __length, int __start, int __range, - struct re_registers *__regs); +extern int re_search (struct re_pattern_buffer *buffer, const char *c_string, + int length, int start, int range, + struct re_registers *regs); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ -extern int re_search_2 (struct re_pattern_buffer *__buffer, - const char *__string1, int __length1, - const char *__string2, int __length2, int __start, - int __range, struct re_registers *__regs, int __stop); +extern int re_search_2 (struct re_pattern_buffer *buffer, + const char *string1, int length1, + const char *string2, int length2, int start, + int range, struct re_registers *regs, int stop); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ -extern int re_match (struct re_pattern_buffer *__buffer, const char *__cstring, - int __length, int __start, struct re_registers *__regs); +extern int re_match (struct re_pattern_buffer *buffer, const char *c_string, + int length, int start, struct re_registers *regs); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 (struct re_pattern_buffer *__buffer, - const char *__string1, int __length1, - const char *__string2, int __length2, int __start, - struct re_registers *__regs, int __stop); +extern int re_match_2 (struct re_pattern_buffer *buffer, + const char *string1, int length1, + const char *string2, int length2, int start, + struct re_registers *regs, int stop); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and @@ -533,10 +533,10 @@ extern int re_match_2 (struct re_pattern_buffer *__buffer, Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -extern void re_set_registers (struct re_pattern_buffer *__buffer, - struct re_registers *__regs, - unsigned int __num_regs, - regoff_t *__starts, regoff_t *__ends); +extern void re_set_registers (struct re_pattern_buffer *buffer, + struct re_registers *regs, + unsigned int num_regs, + regoff_t *starts, regoff_t *ends); #endif /* Use GNU */ #if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_MISC) @@ -569,19 +569,19 @@ extern int re_exec (const char *); #endif /* POSIX compatibility. */ -extern int regcomp (regex_t *__restrict __preg, - const char *__restrict __pattern, - int __cflags); +extern int regcomp (regex_t *__restrict preg, + const char *__restrict pattern, + int cflags); -extern int regexec (const regex_t *__restrict __preg, - const char *__restrict __cstring, size_t __nmatch, - regmatch_t __pmatch[__restrict_arr], - int __eflags); +extern int regexec (const regex_t *__restrict preg, + const char *__restrict c_string, size_t nmatch, + regmatch_t pmatch[__restrict_arr], + int eflags); -extern size_t regerror (int __errcode, const regex_t *__restrict __preg, - char *__restrict __errbuf, size_t __errbuf_size); +extern size_t regerror (int errcode, const regex_t *__restrict preg, + char *__restrict errbuf, size_t errbuf_size); -extern void regfree (regex_t *__preg); +extern void regfree (regex_t *preg); #ifdef __cplusplus diff --git a/regex_internal.c b/regex_internal.c index 056cff3d..9e427081 100644 --- a/regex_internal.c +++ b/regex_internal.c @@ -545,7 +545,10 @@ build_upper_buffer (re_string_t *pstr) int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; if (BE (pstr->trans != NULL, 0)) ch = pstr->trans[ch]; - pstr->mbs[char_idx] = toupper (ch); + if (islower (ch)) + pstr->mbs[char_idx] = toupper (ch); + else + pstr->mbs[char_idx] = ch; } pstr->valid_len = char_idx; pstr->valid_raw_len = char_idx; @@ -683,7 +686,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) pstr->valid_len - offset); pstr->valid_len -= offset; pstr->valid_raw_len -= offset; -#if DEBUG +#if defined DEBUG && DEBUG assert (pstr->valid_len > 0); #endif } @@ -940,7 +943,7 @@ re_string_context_at (const re_string_t *input, int idx, int eflags) int wc_idx = idx; while(input->wcs[wc_idx] == WEOF) { -#ifdef DEBUG +#if defined DEBUG && DEBUG /* It must not happen. */ assert (wc_idx >= 0); #endif @@ -50,7 +50,7 @@ #include "missing_d/memmove.c" #endif /* HAVE_MEMMOVE */ -#ifndef HAVE_STRNCASECMP +#if !defined(HAVE_STRNCASECMP) || !defined(HAVE_STRCASECMP) #include "missing_d/strncasecmp.c" #endif /* HAVE_STRCASE */ @@ -35,8 +35,8 @@ static int var_count; /* total number of global variables and functions */ static NODE *symbol_list; static void (*install_func)(NODE *) = NULL; -static NODE *make_symbol(char *name, NODETYPE type); -static NODE *install(char *name, NODE *parm, NODETYPE type); +static NODE *make_symbol(const char *name, NODETYPE type); +static NODE *install(const char *name, NODE *parm, NODETYPE type); static void free_bcpool(INSTRUCTION *pl); static AWK_CONTEXT *curr_ctxt = NULL; @@ -75,7 +75,7 @@ init_symbol_table() */ NODE * -install_symbol(char *name, NODETYPE type) +install_symbol(const char *name, NODETYPE type) { return install(name, NULL, type); } @@ -112,14 +112,12 @@ lookup(const char *name) continue; n = in_array(tables[i], tmp); - if (n != NULL) { - unref(tmp); - return n; - } + if (n != NULL) + break; } unref(tmp); - return n; /* NULL */ + return n; /* NULL or new place */ } /* make_params --- allocate function parameters for the symbol table */ @@ -155,11 +153,13 @@ install_params(NODE *func) if (func == NULL) return; + assert(func->type == Node_func); - if ((pcount = func->param_cnt) <= 0 - || (parms = func->fparms) == NULL - ) + + if ( (pcount = func->param_cnt) <= 0 + || (parms = func->fparms) == NULL) return; + for (i = 0; i < pcount; i++) (void) install(parms[i].param, parms + i, Node_param_list); } @@ -177,10 +177,11 @@ remove_params(NODE *func) if (func == NULL) return; + assert(func->type == Node_func); - if ((pcount = func->param_cnt) <= 0 - || (parms = func->fparms) == NULL - ) + + if ( (pcount = func->param_cnt) <= 0 + || (parms = func->fparms) == NULL) return; for (i = pcount - 1; i >= 0; i--) { @@ -191,11 +192,11 @@ remove_params(NODE *func) assert(p->type == Node_param_list); tmp = make_string(p->vname, strlen(p->vname)); tmp2 = in_array(param_table, tmp); - if (tmp2 != NULL && tmp2->dup_ent != NULL) { + if (tmp2 != NULL && tmp2->dup_ent != NULL) tmp2->dup_ent = tmp2->dup_ent->dup_ent; - } else { + else (void) assoc_remove(param_table, tmp); - } + unref(tmp); } @@ -274,7 +275,7 @@ destroy_symbol(NODE *r) /* make_symbol --- allocates a global symbol for the symbol table. */ static NODE * -make_symbol(char *name, NODETYPE type) +make_symbol(const char *name, NODETYPE type) { NODE *r; @@ -284,7 +285,7 @@ make_symbol(char *name, NODETYPE type) null_array(r); else if (type == Node_var) r->var_value = dupnode(Nnull_string); - r->vname = name; + r->vname = (char *) name; r->type = type; return r; @@ -293,7 +294,7 @@ make_symbol(char *name, NODETYPE type) /* install --- install a global name or function parameter in the symbol table */ static NODE * -install(char *name, NODE *parm, NODETYPE type) +install(const char *name, NODE *parm, NODETYPE type) { NODE *r; NODE **aptr; @@ -306,20 +307,22 @@ install(char *name, NODE *parm, NODETYPE type) if (type == Node_param_list) { table = param_table; - } else if (type == Node_func || type == Node_ext_func) { + } else if ( type == Node_func + || type == Node_ext_func + || type == Node_builtin_func) { table = func_table; } else if (installing_specials) { table = global_table; } - if (parm != NULL) { + if (parm != NULL) r = parm; - } else { + else { /* global symbol */ r = make_symbol(name, type); if (type == Node_func) func_count++; - if (type != Node_ext_func && table != global_table) + if (type != Node_ext_func && type != Node_builtin_func && table != global_table) var_count++; /* total, includes Node_func */ } @@ -344,7 +347,6 @@ simple: return r; } - /* comp_symbol --- compare two (variable or function) names */ static int @@ -393,7 +395,7 @@ get_symbols(SYMBOL_TYPE what, bool sort) for (i = count = 0; i < max; i += 2) { r = list[i+1]; - if (r->type == Node_ext_func) + if (r->type == Node_ext_func || r->type == Node_builtin_func) continue; assert(r->type == Node_func); table[count++] = r; @@ -517,7 +519,8 @@ release_symbols(NODE *symlist, int keep_globals) for (p = symlist->rnode; p != NULL; p = next) { if (! keep_globals) { - /* destroys globals, function, and params + /* + * destroys globals, function, and params * if still in symbol table */ destroy_symbol(p->lnode); @@ -538,7 +541,7 @@ load_symbols() NODE *sym_array; NODE **aptr; long i, j, max; - NODE *user, *extension, *untyped, *scalar, *array; + NODE *user, *extension, *untyped, *scalar, *array, *built_in; NODE **list; NODE *tables[4]; @@ -569,6 +572,7 @@ load_symbols() scalar = make_string("scalar", 6); untyped = make_string("untyped", 7); array = make_string("array", 5); + built_in = make_string("builtin", 7); for (i = 0; tables[i] != NULL; i++) { list = assoc_list(tables[i], "@unsorted", ASORTI); @@ -579,6 +583,7 @@ load_symbols() r = list[j+1]; if ( r->type == Node_ext_func || r->type == Node_func + || r->type == Node_builtin_func || r->type == Node_var || r->type == Node_var_array || r->type == Node_var_new) { @@ -593,6 +598,9 @@ load_symbols() case Node_func: *aptr = dupnode(user); break; + case Node_builtin_func: + *aptr = dupnode(built_in); + break; case Node_var: *aptr = dupnode(scalar); break; diff --git a/test/ChangeLog b/test/ChangeLog index 61b8cd3b..0cd7e5f3 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,28 @@ +2014-09-10 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok, profile4.ok, profile5.ok: Update for new code. + +2014-09-05 Arnold D. Robbins <arnold@skeeve.com> + + * functab4.awk: Changed to use stat instead of chdir since + /tmp isn't /tmp on all systems (e.g. Mac OS X). Thanks to + Hermann Peifer for the report. + + Sort of related: + + * indirectcall2.awk, indirectcall2.ok: New files. + * id.ok: Updated. + +2014-09-04 Arnold D. Robbins <arnold@skeeve.com> + + * profile2.ok: Update after code improvement in profiler. + * functab4.ok: Update after making indirect calls of + extension functions work. :-) + +2014-08-15 Arnold D. Robbins <arnold@skeeve.com> + + * badargs.ok: Adjust after revising text for -L option. + 2014-08-12 Arnold D. Robbins <arnold@skeeve.com> * ofs1.ok: Updated to match corrected behavior in gawk. diff --git a/test/Makefile.am b/test/Makefile.am index 65952acd..3b53ea9f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -421,6 +421,8 @@ EXTRA_DIST = \ indirectcall.awk \ indirectcall.in \ indirectcall.ok \ + indirectcall2.awk \ + indirectcall2.ok \ inftest.awk \ inftest.ok \ inplace.in \ @@ -1010,7 +1012,7 @@ GAWK_EXT_TESTS = \ gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectcall \ + include include2 indirectcall indirectcall2 \ lint lintold lintwarn \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ diff --git a/test/Makefile.in b/test/Makefile.in index 71593576..4cd850f5 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -667,6 +667,8 @@ EXTRA_DIST = \ indirectcall.awk \ indirectcall.in \ indirectcall.ok \ + indirectcall2.awk \ + indirectcall2.ok \ inftest.awk \ inftest.ok \ inplace.in \ @@ -1255,7 +1257,7 @@ GAWK_EXT_TESTS = \ gensub gensub2 getlndir gnuops2 gnuops3 gnureops \ icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectcall \ + include include2 indirectcall indirectcall2 \ lint lintold lintwarn \ manyfiles match1 match2 match3 mbstr1 \ nastyparm next nondec nondec2 \ @@ -3474,6 +3476,11 @@ indirectcall: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +indirectcall2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lint: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 0841ae77..5c34af9e 100644 --- a/test/Maketests +++ b/test/Maketests @@ -1082,6 +1082,11 @@ indirectcall: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +indirectcall2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lint: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/badargs.ok b/test/badargs.ok index 8d34be1f..1664ec1c 100644 --- a/test/badargs.ok +++ b/test/badargs.ok @@ -17,7 +17,7 @@ Short options: GNU long options: (extensions) -h --help -i includefile --include=includefile -l library --load=library - -L [fatal] --lint[=fatal] + -L[fatal|invalid] --lint[=fatal|invalid] -M --bignum -N --use-lc-numeric -n --non-decimal-data diff --git a/test/functab4.awk b/test/functab4.awk index 0d9d4267..196fcc6d 100644 --- a/test/functab4.awk +++ b/test/functab4.awk @@ -6,9 +6,25 @@ function foo() } BEGIN { - x = FUNCTAB["chdir"] - print "x =", x - @x("/tmp") - printf "we are now in --> " - system("/bin/pwd || /usr/bin/pwd") + f = FUNCTAB["foo"] + @f() + + ret1 = stat(".", data1) + print "ret1 =", ret1 + + f = "stat" + ret2 = @f(".", data2) + print "ret2 =", ret2 + + problem = 0 + for (i in data1) { + if (! isarray(data1[i])) { +# print i, data1[i] + if (! (i in data2) || data1[i] != data2[i]) { + printf("mismatch element \"%s\"\n", i) + problems++ + } + } + } + print(problems ? (problems+0) "encountered" : "no problems encountered") } diff --git a/test/functab4.ok b/test/functab4.ok index 70a520b7..2b76cd88 100644 --- a/test/functab4.ok +++ b/test/functab4.ok @@ -1,3 +1,4 @@ -x = chdir -gawk: functab4.awk:11: fatal: cannot (yet) call extension functions indirectly -EXIT CODE: 2 +foo! +ret1 = 0 +ret2 = 0 +no problems encountered @@ -1,32 +1,73 @@ -FUNCTAB -> array -ARGV -> array -SYMTAB -> array -ORS -> scalar -ROUNDMODE -> scalar -i -> untyped OFS -> scalar +rand -> builtin +ARGC -> scalar +dcgettext -> builtin +gsub -> builtin +PREC -> scalar +match -> builtin +ARGIND -> scalar +int -> builtin ERRNO -> scalar +ARGV -> array +log -> builtin +sprintf -> builtin +ROUNDMODE -> scalar +strftime -> builtin +systime -> builtin +and -> builtin +srand -> builtin FNR -> scalar +asort -> builtin +atan2 -> builtin +cos -> builtin +TEXTDOMAIN -> scalar +ORS -> scalar +split -> builtin +div -> builtin +RSTART -> scalar +compl -> builtin +bindtextdomain -> builtin +exp -> builtin +or -> builtin +fflush -> builtin +gensub -> builtin LINT -> scalar +dcngettext -> builtin +index -> builtin IGNORECASE -> scalar -NR -> scalar -function1 -> user -ARGIND -> scalar -NF -> scalar -TEXTDOMAIN -> scalar +system -> builtin CONVFMT -> scalar +sqrt -> builtin +rshift -> builtin +tolower -> builtin +FS -> scalar +BINMODE -> scalar +sin -> builtin +asorti -> builtin FIELDWIDTHS -> scalar -ARGC -> scalar +function1 -> user +FILENAME -> scalar +close -> builtin +mktime -> builtin +FUNCTAB -> array +NF -> scalar +isarray -> builtin an_array -> untyped -PROCINFO -> array -PREC -> scalar +patsplit -> builtin +NR -> scalar SUBSEP -> scalar -FPAT -> scalar -RS -> scalar -FS -> scalar +extension -> builtin +i -> untyped +sub -> builtin OFMT -> scalar RLENGTH -> scalar +substr -> builtin +FPAT -> scalar +RS -> scalar +xor -> builtin RT -> scalar -BINMODE -> scalar -FILENAME -> scalar -RSTART -> scalar +PROCINFO -> array +lshift -> builtin +SYMTAB -> array +strtonum -> builtin +toupper -> builtin diff --git a/test/indirectcall2.awk b/test/indirectcall2.awk new file mode 100644 index 00000000..8f3c9483 --- /dev/null +++ b/test/indirectcall2.awk @@ -0,0 +1,11 @@ +BEGIN { + Quarter_pi = 3.1415927 / 4 + print sin(Quarter_pi) + + f = "sin" + print @f(Quarter_pi) + + print substr("abcdefgh", 2, 3) + f = "substr" + print @f("abcdefgh", 2, 3) +} diff --git a/test/indirectcall2.ok b/test/indirectcall2.ok new file mode 100644 index 00000000..05bee4b1 --- /dev/null +++ b/test/indirectcall2.ok @@ -0,0 +1,4 @@ +0.707107 +0.707107 +bcd +bcd diff --git a/test/profile2.ok b/test/profile2.ok index 77169336..50c7e190 100644 --- a/test/profile2.ok +++ b/test/profile2.ok @@ -1,34 +1,19 @@ # BEGIN block(s) BEGIN { - # xref.awk - cross reference an awk program - # 12/2010: Modified for gawk test suite to use a variable - # for the sort command and to use `sort -k1' instead of `sort +1' - # "sort -k1" - # create array of keywords to be ignored by lexer 1 if (sortcmd == "") { sortcmd = "sort" } - # build the symbol-state table 1 asplit("BEGIN:END:atan2:break:close:continue:cos:delete:" "do:else:exit:exp:for:getline:gsub:if:in:index:int:" "length:log:match:next:print:printf:rand:return:sin:" "split:sprintf:sqrt:srand:sub:substr:system:while", keywords, ":") - # parse the input and store an intermediate representation - # of the cross-reference information - # set up the machine 1 split("00:00:00:00:00:00:00:00:00:00:" "20:10:10:12:12:11:07:00:00:00:" "08:08:08:08:08:33:08:00:00:00:" "08:44:08:36:08:08:08:00:00:00:" "08:44:45:42:42:41:08", machine, ":") - # run the machine 1 state = 1 - # finished parsing, now ready to print output - 571 for (; ; ) { - # get next symbol + 571 for (;;) { 571 symb = lex() 571 nextstate = substr(machine[state symb], 1, 1) - # perform required action 571 act = substr(machine[state symb], 2, 1) - # finished with current token 571 if (act == "0") { # 12 559 } else { 559 if (act == "1") { # 8 - # do nothing 8 if (! inarray(tok, names)) { # 3 3 names[++nnames] = tok } @@ -108,7 +93,6 @@ 1 function asplit(str, arr, fs, n) { - # END OF PROGRAM 1 n = split(str, temp_asplit, fs) 36 for (i = 1; i <= n; i++) { 36 arr[temp_asplit[i]]++ @@ -125,7 +109,7 @@ 571 function lex() { - 1702 for (; ; ) { + 1702 for (;;) { 1702 if (tok == "(eof)") { return 7 } @@ -135,13 +119,9 @@ 1 return 7 } } - # remove white space, 1701 sub(/^[ \t]+/, "", line) - # quoted strings, 1701 sub(/^"([^"]|\\")*"/, "", line) - # regular expressions, 1701 sub(/^\/([^\/]|\\\/)+\//, "", line) - # and comments 1701 sub(/^#.*/, "", line) 1701 if (line ~ /^function/) { # 4 4 tok = "function" @@ -159,7 +139,6 @@ 53 return 3 1591 } else { 1591 if (match(line, /^[[:alpha:]_][[:alnum:]]*\[/)) { # 43 - # change regexes to use posix character classes 43 tok = substr(line, 1, RLENGTH - 1) 43 line = substr(line, RLENGTH + 1) 43 return 5 diff --git a/test/profile4.ok b/test/profile4.ok index 8ff4470f..9d2b9430 100644 --- a/test/profile4.ok +++ b/test/profile4.ok @@ -1,11 +1,9 @@ - # BEGIN block(s) - - BEGIN { - a = "foo" (c = "bar") - a = (b - c) "foo" - a = "foo" (b - c) - q = (d = "x") (e = "y") - a = (c = tolower("FOO")) in JUNK - x = y == 0 && z == 2 && q == 45 - } +BEGIN { + a = "foo" (c = "bar") + a = (b - c) "foo" + a = "foo" (b - c) + q = (d = "x") (e = "y") + a = (c = tolower("FOO")) in JUNK + x = y == 0 && z == 2 && q == 45 +} diff --git a/test/profile5.ok b/test/profile5.ok index 3e0736d5..4c944627 100644 --- a/test/profile5.ok +++ b/test/profile5.ok @@ -1,5815 +1,5728 @@ - # BEGIN block(s) +BEGIN { + _addlib("_BASE") +} + +############################################################################ + +BEGIN { + BINMODE = "rw" + SUBSEP = "\000" + _NULARR[""] + delete _NULARR[""] + _INITBASE() +} + +BEGIN { + _addlib("_sYS") +} + +BEGIN { + _addlib("_rEG") +} + +BEGIN { + _addlib("_INSTRUC") +} + +############################################################################# + +BEGIN { + _delay_perfmsdelay = 11500 +} + +BEGIN { + _addlib("_ARR") +} + +#___________________________________________________________________________________ +BEGIN { +} + +########################################################################### + + + + + + +BEGIN { + _addlib("_EXTFN") +} + +############################################################################# + +BEGIN { + delete _XCHR + delete _ASC + delete _CHR + t = "" + for (i = 0; i < 256; i++) { + _ASC[a = _CHR[i] = sprintf("%c", i)] = i + _QASC[a] = sprintf("%.3o", i) + _XCHR[_CHR[i]] = sprintf("%c", (i < 128 ? i + 128 : i - 128)) + } + #_____________________________________________________________________________ + + for (i = 0; i < 256; i++) { + _QSTRQ[_CHR[i]] = "\\" sprintf("%.3o", i) + } + #_______________________________________________________________________ + + for (i = 0; i < 32; i++) { + _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + for (; i < 128; i++) { + _QSTR[_CHR[i]] = _CHR[i] + } + for (; i < 256; i++) { + _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + _QSTR["\\"] = "\\\\" + #; _QSTR["\""]="\\\"" + #_____________________________________________________________________________ + + _CHR["CR"] = "\r" + _CHR["EOL"] = "\r\n" + _CHR["EOF"] = "\032" + _QSTR[_CHR["EOL"]] = "\\015\\012" + #_______________________________________________________________________ + + _CHR["MONTH"][_CHR["MONTH"]["Jan"] = "01"] = "Jan" + _CHR["MONTH"][_CHR["MONTH"]["Feb"] = "02"] = "Feb" + _CHR["MONTH"][_CHR["MONTH"]["Mar"] = "03"] = "Mar" + _CHR["MONTH"][_CHR["MONTH"]["Apr"] = "04"] = "Apr" + _CHR["MONTH"][_CHR["MONTH"]["May"] = "05"] = "May" + _CHR["MONTH"][_CHR["MONTH"]["Jun"] = "06"] = "Jun" + _CHR["MONTH"][_CHR["MONTH"]["Jul"] = "07"] = "Jul" + _CHR["MONTH"][_CHR["MONTH"]["Aug"] = "08"] = "Aug" + _CHR["MONTH"][_CHR["MONTH"]["Sep"] = "09"] = "Sep" + _CHR["MONTH"][_CHR["MONTH"]["Oct"] = "10"] = "Oct" + _CHR["MONTH"][_CHR["MONTH"]["Nov"] = "11"] = "Nov" + _CHR["MONTH"][_CHR["MONTH"]["Dec"] = "12"] = "Dec" + #_____________________________________________________________________________ + + _TAB_STEP_DEFAULT = 8 + #_____________________________________________________________________________ + + for (i = 0; i < 32; i++) { + _REXPSTR[_CHR[i]] = _QSTRQ[_CHR[i]] + } + for (; i < 256; i++) { + _REXPSTR[_CHR[i]] = _CHR[i] + } + _gensubfn("\\^$.()|{,}[-]?+*", ".", "_rexpstr_i0") +} + +BEGIN { + _addlib("_SYSIO") +} + +############################################################################# + +BEGIN { + _SYS_STDCON = "CON" + _CON_WIDTH = (match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80) +} + +BEGIN { + _addlib("_FILEIO") +} + +############################################################################# + +BEGIN { + if (_SYS_STDOUT == "") { + _SYS_STDOUT = "/dev/stdout" + } + if (_SYS_STDERR == "") { + _SYS_STDERR = "/dev/stderr" + } + _CHR["SUBDIR"] = "\\" + if (_gawk_scriptlevel < 1) { + match(b = _cmd("echo %CD% 2>NUL"), /[^\x00-\x1F]*/) + ENVIRON["CD"] = _FILEIO_RD = _filerd(substr(b, RSTART, RLENGTH) _CHR["SUBDIR"]) + _FILEIO_R = _filer(_FILEIO_RD) + _FILEIO_D = _filed(_FILEIO_RD) + _setmpath(_filerd(_FILEIO_RD "_tmp" _CHR["SUBDIR"])) + } +} + +BEGIN { + _addlib("_tOBJ") +} + +############################################################################# +BEGIN { + _tInBy = "\212._tInBy" + _tgenuid_init() + _UIDS[""] + delete _UIDS[""] + _UIDSDEL[""] + delete _UIDSDEL[""] + _tPREV[""] + _tPARENT[""] + _tNEXT[""] + _tFCHLD[""] + _tQCHLD[""] + _tLCHLD[""] + _tLINK[""] + _tCLASS[""] + _tSTR[""] + _tDLINK[""] + _[""] + delete _[""] + _ptr[""] + delete _ptr[""] + _TMP0[""] + delete _TMP0[""] + _TMP1[""] + delete _TMP1[""] +} + +BEGIN { + _addlib("_ERRLOG") +} + +############################################################################# + +BEGIN { + if (_gawk_scriptlevel < 1) { + _ERRLOG_TF = 1 + _ERRLOG_VF = 1 + _ERRLOG_IF = 1 + _ERRLOG_WF = 1 + _ERRLOG_EF = 1 + _ERRLOG_FF = 1 + _wrfile(_errlog_file = _getmpfile("OUTPUT.LOG"), "") + } +} + +BEGIN { + _addlib("_SHORTCUT") +} + +#___________________________________________________________________________________ +BEGIN { + _shortcut_init() +} + +######################################################### + + + +BEGIN { + _addlib("_eXTFN") +} + +#___________________________________________________________________________________ +BEGIN { + _extfn_init() +} + +############################################################ + + +BEGIN { + _addlib("_sHARE") +} + +BEGIN { + _addlib("_FILEVER") +} + +BEGIN { + _addlib("_DS") + ############################################################################### + + _PRODUCT_NAME = "Deployment Solution Control" + _PRODUCT_VERSION = "1.0" + _PRODUCT_COPYRIGHT = "Copyright (C) 2013 by CosumoGEN" + _PRODUCT_FILENAME = "_main.ewk" +} + +# problem configuring uid by array charset: i can' understand what format of the array: possibly - remove array support +# after removal of array format detection: there is unfinished conflicts: it is possible to totally remove array uid-gen initialization + +#_____________________________________________________ +BEGIN { + _inituidefault() +} + +#_____________________________________________________ +BEGIN { + _initfilever() +} + +#_____________________________________________________ +BEGIN { + _initshare() +} + +#_________________________________________________________________ +BEGIN { + _inspass(_IMPORT, "_import_data") +} + +#_______________________________________________ +BEGIN { + _TEND[_ARRLEN] = 0 + _TYPEWORD = "_TYPE" +} + +#_______________________________________________ +BEGIN { + _ARRLEN = "\032LEN" + _ARRPTR = "\032PTR" + _ARRSTR = "" +} + +#_____________________________________________________ +BEGIN { + _getperf_fn = "_nop" +} + +BEGIN { + _datablock_length = 262144 +} + +#_____________________________________________________ +BEGIN { + _initrdreg() +} + +#_____________________________________________________ +BEGIN { + _initregpath0() +} - BEGIN { - _addlib("_BASE") - } +#_____________________________________________________ +BEGIN { + _initsys() +} - BEGIN { - #___________________________________________________________________________________ - ############################################################################ - BINMODE = "rw" - SUBSEP = "\000" - _NULARR[""] - delete _NULARR[""] - _INITBASE() +############################################################################ + +BEGIN { + a = ENVIRON["EGAWK_CMDLINE"] + gsub(/^[ \t]*/, "", a) + a = _lib_CMDLN(a) + if (a != "" && ! _LIBAPI["F"]["!"]) { + _out(_lib_HELP()) + _fatal("Bad comandline argument `" a "'") + } + gsub(/^[ \t]*/, "", a) + ENVIRON["EGAWK_CMDLINE"] = a + _lib_APPLY() + if (_basexit_fl) { + exit + } + _INIT() + _START() + _END() +} + +######################################################################## + +END { + _EXIT() +} + +############################################################################### + +END { + if (_gawk_scriptlevel < 1) { + close(_errlog_file) + p = _Zimport(_rdfile(_errlog_file), _N()) + if ((t = _get_errout(p)) != "") { + _expout(t, "/dev/stderr") + } + } +} + +############################################################################### + +END { + if (_gawk_scriptlevel < 1) { + if (! _fileio_notdeltmpflag) { + _FILEIO_TMPATHS[_FILEIO_TMPRD] + _Foreach(_FILEIO_TMPATHS, "_uninit_del") + } + } +} + +############################################################################### +END { + if (_constatstrln > 0) { + _constat() } +} - BEGIN { - _addlib("_sYS") - } +#___________________________________________________________________________________ +#################################################################################### - BEGIN { - _addlib("_rEG") - } - BEGIN { - _addlib("_INSTRUC") - } - BEGIN { - #___________________________________________________________________________________ - ############################################################################# - _delay_perfmsdelay = 11500 - } - BEGIN { - _addlib("_ARR") - } - BEGIN { - } - BEGIN { - #___________________________________________________________________________________ - ########################################################################### - _addlib("_EXTFN") - } - BEGIN { - #___________________________________________________________________________________ - ############################################################################# - delete _XCHR - delete _ASC - delete _CHR - t = "" - #_____________________________________________________________________________ - for (i = 0; i < 256; i++) { - _ASC[a = _CHR[i] = sprintf("%c", i)] = i - _QASC[a] = sprintf("%.3o", i) - _XCHR[_CHR[i]] = sprintf("%c", (i < 128 ? i + 128 : i - 128)) - } - #_______________________________________________________________________ - for (i = 0; i < 256; i++) { - _QSTRQ[_CHR[i]] = "\\" sprintf("%.3o", i) - } - for (i = 0; i < 32; i++) { - _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - for (; i < 128; i++) { - _QSTR[_CHR[i]] = _CHR[i] - } - for (; i < 256; i++) { - _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - #; _QSTR["\""]="\\\"" - #_____________________________________________________________________________ - _QSTR["\\"] = "\\\\" - _CHR["CR"] = "\r" - _CHR["EOL"] = "\r\n" - _CHR["EOF"] = "\032" - #_______________________________________________________________________ - _QSTR[_CHR["EOL"]] = "\\015\\012" - _CHR["MONTH"][_CHR["MONTH"]["Jan"] = "01"] = "Jan" - _CHR["MONTH"][_CHR["MONTH"]["Feb"] = "02"] = "Feb" - _CHR["MONTH"][_CHR["MONTH"]["Mar"] = "03"] = "Mar" - _CHR["MONTH"][_CHR["MONTH"]["Apr"] = "04"] = "Apr" - _CHR["MONTH"][_CHR["MONTH"]["May"] = "05"] = "May" - _CHR["MONTH"][_CHR["MONTH"]["Jun"] = "06"] = "Jun" - _CHR["MONTH"][_CHR["MONTH"]["Jul"] = "07"] = "Jul" - _CHR["MONTH"][_CHR["MONTH"]["Aug"] = "08"] = "Aug" - _CHR["MONTH"][_CHR["MONTH"]["Sep"] = "09"] = "Sep" - _CHR["MONTH"][_CHR["MONTH"]["Oct"] = "10"] = "Oct" - _CHR["MONTH"][_CHR["MONTH"]["Nov"] = "11"] = "Nov" - #_____________________________________________________________________________ - _CHR["MONTH"][_CHR["MONTH"]["Dec"] = "12"] = "Dec" - #_____________________________________________________________________________ - _TAB_STEP_DEFAULT = 8 - for (i = 0; i < 32; i++) { - _REXPSTR[_CHR[i]] = _QSTRQ[_CHR[i]] - } - for (; i < 256; i++) { - _REXPSTR[_CHR[i]] = _CHR[i] - } - _gensubfn("\\^$.()|{,}[-]?+*", ".", "_rexpstr_i0") - } - - BEGIN { - _addlib("_SYSIO") - } +# make sure that stdout contain only expected characters +# make sure that stderr contain only expected characters +# redesign & reformat keys and its outputs +# try different key combinations +# add lib-specified to all libs - BEGIN { - #___________________________________________________________________________________ - ############################################################################# - _SYS_STDCON = "CON" - _CON_WIDTH = (match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80) - } - BEGIN { - _addlib("_FILEIO") - } - - BEGIN { - #___________________________________________________________________________________ - ############################################################################# - if (_SYS_STDOUT == "") { - _SYS_STDOUT = "/dev/stdout" - } - if (_SYS_STDERR == "") { - _SYS_STDERR = "/dev/stderr" - } - _CHR["SUBDIR"] = "\\" - if (_gawk_scriptlevel < 1) { - match(b = _cmd("echo %CD% 2>NUL"), /[^\x00-\x1F]*/) - ENVIRON["CD"] = _FILEIO_RD = _filerd(substr(b, RSTART, RLENGTH) _CHR["SUBDIR"]) - _FILEIO_R = _filer(_FILEIO_RD) - _FILEIO_D = _filed(_FILEIO_RD) - _setmpath(_filerd(_FILEIO_RD "_tmp" _CHR["SUBDIR"])) +#_______________________________________________________________________ +function W(p, p0, p1) +{ + ##################################################### + if (isarray(p0)) { + delete p0[p] + if (isarray(p1)) { + for (i in p1) { + if (isarray(p1[i])) { + p0[p][i][""] + delete p0[p][i][""] + _N_i0(p0[p][i], p1[i]) + } else { + p0[p][i] = p1[i] + } + } + return p } + return (p0[p] = p1) } - - BEGIN { - _addlib("_tOBJ") - } - - BEGIN { - #___________________________________________________________________________________ - ############################################################################# - _tInBy = "\212._tInBy" - _tgenuid_init() - _UIDS[""] - delete _UIDS[""] - _UIDSDEL[""] - delete _UIDSDEL[""] - _tPREV[""] - _tPARENT[""] - _tNEXT[""] - _tFCHLD[""] - _tQCHLD[""] - _tLCHLD[""] - _tLINK[""] - _tCLASS[""] - _tSTR[""] - _tDLINK[""] - _[""] - delete _[""] - _ptr[""] - delete _ptr[""] - _TMP0[""] - delete _TMP0[""] - _TMP1[""] - delete _TMP1[""] - } - - BEGIN { - _addlib("_ERRLOG") - } - - BEGIN { - if (_gawk_scriptlevel < 1) { - #___________________________________________________________________________________ - ############################################################################# - _ERRLOG_TF = 1 - _ERRLOG_VF = 1 - _ERRLOG_IF = 1 - _ERRLOG_WF = 1 - _ERRLOG_EF = 1 - _ERRLOG_FF = 1 - _wrfile(_errlog_file = _getmpfile("OUTPUT.LOG"), "") + delete _[p][p0] + if (isarray(p1)) { + for (i in p1) { + if (isarray(p1[i])) { + _[p][p0][i][""] + delete _[p][p0][i][""] + _N_i0(_[p][p0][i], p1[i]) + } else { + _[p][p0][i] = p1[i] + } } + return p } + return (_[p][p0] = p1) +} - BEGIN { - _addlib("_SHORTCUT") - } - - BEGIN { - #___________________________________________________________________________________ - _shortcut_init() - } - - BEGIN { - ######################################################### - _addlib("_eXTFN") - } +########################################################## - BEGIN { - #___________________________________________________________________________________ - _extfn_init() - } - - BEGIN { - ############################################################ - _addlib("_sHARE") +function _ARR(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_ARR 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - BEGIN { - _addlib("_FILEVER") - } +########################################################## - BEGIN { - ############################################################################### - _addlib("_DS") - _PRODUCT_NAME = "Deployment Solution Control" - _PRODUCT_VERSION = "1.0" - _PRODUCT_COPYRIGHT = "Copyright (C) 2013 by CosumoGEN" - _PRODUCT_FILENAME = "_main.ewk" +function _BASE(c, t, P, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^((--([Vv])ersion)|(-([Vv])))[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + _cmdln_version = A[3] A[5] + } else { + if (match(t, /^((-?\?)|(--help))[ \t]*/)) { + t = substr(t, RLENGTH + 1) + _cmdln_help = 1 + } else { + if (match(t, /^--[ \t]*/)) { + return _endpass(substr(t, RLENGTH + 1)) + } + } + } + return t + #___________________________________________________________ + + case "_lib_APPLY": + if (_cmdln_help) { + match(_fbaccr(_LIBAPI, "_lib_HELP"), /^([^\x00]*)\x00([^\x01]*)\x01(.*)/, A) + _out(A[2] A[1] A[3]) + return _endpass(_basexit_fl = 1) + } + if (_cmdln_version) { + _out(_ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() ((_cmdln_version == "v" ? "" : _lib_NAMEVER()))) + return _endpass(_basexit_fl = 1) + } + return + #___________________________________________________________ + + case "_lib_HELP": + return ("\000" _ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() _ln(" Usage:") _ln() _ln(" " _PRODUCT_FILENAME " [/key1 /key2...] [-- cmdline]") _ln() _ln(" keys:") _ln() "\001" _ln(" -v -V --version - output product version and (if /V) all modules") _ln(" ? -? --help - output this help page") _ln(" -- - command line string edge")) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_BASE 3.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - BEGIN { - # problem configuring uid by array charset: i can' understand what format of the array: possibly - remove array support - # after removal of array format detection: there is unfinished conflicts: it is possible to totally remove array uid-gen initialization +#____________________________________________________________________________ +function _DS(c, t, P, a, A) +{ + ###################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t #_____________________________________________________ - _inituidefault() - } - - BEGIN { + case "_lib_APPLY": + return #_____________________________________________________ - _initfilever() - } - - BEGIN { + case "_lib_HELP": + return (_ln() _ln(" Usage: " _PRODUCT_NAME " [/key1 /key2...] sourcefile [cmdline]") _ln()) #_____________________________________________________ - _initshare() - } - - BEGIN { - #_________________________________________________________________ - _inspass(_IMPORT, "_import_data") - } - - BEGIN { - #_______________________________________________ - _TEND[_ARRLEN] = 0 - _TYPEWORD = "_TYPE" - } - - BEGIN { - #_______________________________________________ - _ARRLEN = "\032LEN" - _ARRPTR = "\032PTR" - _ARRSTR = "" - } - - BEGIN { + case "_lib_NAMEVER": + return #_____________________________________________________ - _getperf_fn = "_nop" - } - - BEGIN { - _datablock_length = 262144 - } - - BEGIN { + case "_lib_BEGIN": + return #_____________________________________________________ - _initrdreg() + case "_lib_END": + return } +} - BEGIN { - #_____________________________________________________ - _initregpath0() - } +#______________________________________________________________________________________________ +function _END() +{ + ################################################################################# + +} - BEGIN { - #_____________________________________________________________________________ - ################################################################ - #_____________________________________________________ - _initsys() - } - - 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 - ############################################################################ - a = ENVIRON["EGAWK_CMDLINE"] - gsub(/^[ \t]*/, "", a) - a = _lib_CMDLN(a) - if (a != "" && ! _LIBAPI["F"]["!"]) { - _out(_lib_HELP()) - _fatal("Bad comandline argument `" a "'") - } - gsub(/^[ \t]*/, "", a) - ENVIRON["EGAWK_CMDLINE"] = a - _lib_APPLY() - if (_basexit_fl) { - exit - } - _INIT() - _START() - _END() - } - - # END block(s) - - END { - #_____________________________________________________________________________ - ######################################################################## - _EXIT() - } - - END { - if (_gawk_scriptlevel < 1) { - #_______________________________________________________________________ - ######################################################################## - ############################################################################### - close(_errlog_file) - p = _Zimport(_rdfile(_errlog_file), _N()) - if ((t = _get_errout(p)) != "") { - _expout(t, "/dev/stderr") - } - } - } +######################################################## - END { - if (_gawk_scriptlevel < 1) { - if (! _fileio_notdeltmpflag) { - ########################################################################################## - # PUBLIC: - #_____________________________________________________________________________ - # _rFBRO(ptr) - Return ptr of first-bro. [TESTED] - # If !ptr then returns "". - #_____________________________________________________________________________ - # _rLBRO(ptr) - Return ptr of last-bro. [TESTED] - # If !ptr then returns "". - #_____________________________________________________________________________ - # _rQBRO(ptr) - Returns brothers total quantity. [TESTED] - # If !ptr then returns "". - ############################################################################### - _FILEIO_TMPATHS[_FILEIO_TMPRD] - _Foreach(_FILEIO_TMPATHS, "_uninit_del") - } +function _ERRLOG(c, t, P, a, b, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^[ \t]*-L:([TtVvIiWwEeFf]*)[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + _errlog_errflkey = _errlog_errflkey A[1] } - } - - END { - #___________________________________________________________________________________ - #################################################################################### - #___________________________________________________________________________________ - # fn _dirtree(array,pathmask) - # - # Return in `array' file tree from pathmask: - # array["file.filerdne"]="size date time" - # array["subdir.filerd"]["file.filerdne"]="size date time" - # array["subdir.filerd"]["file.filerd"][...] - # - # The array will be cleared before any action. Function return pathmask w/o ltabspc and rtabspc. - #___________________________________________________________________________________ - # OK: change internal function's names to: w\o "_" - # OK: FLENGTH: should cover r-spcs - # OK: optimize REXP - # OK: add new symbols to dir/file names ( ! and + ) - # OK: create _getfilepath() - # OK: del - conflict with WROOTDIR (do not update it) - # OK: dir/del - support for filemask ( * and ? ) - # OK: how to define code injections: header\ender; and HANDLERS - # OK: units in header\ender? conline division... - # OK: _FILEPATH problem: it will not been defined at the moment when subscript0 starts - at the start TMPRD="_tmp" - # OK: del: if del("dir\\") - then all ok except it NOT deleted "dir\\" - _del function removed(renamed to __del) - # OK: tmpdirs: it delete only autotmp dir and only from script0 - # OK: MICROTEST: global testing of filepath (UNC! CORRECT RESULTS! ) - # question about cache: did new just now generated absolute filepath cached in FILECACHE? its seems like NO - # check _untmp: CONFLICT: if file or dir from autotmp dir will be untmp then it anyway will be deleted; but file or dir from other point never be deleted anyway - so what is the point of untmp????? - #ERRLOG: _setmpath: warning!!!!! - #___________________________________________________________________________________ - #################################################################################### - # PUBLIC: - #___________________________________________________________________________________ - # - # fn _rdfile(_filepath) - # - # Read and return data from file specified in _filepath. - # If _filepath=="" then no action occured and return "". - # Function read and return data from file. No any changes in data occured. - # Function use _filerdne function internally. If some syntax error - # found in _filepath then function return "". - # If some error occured while reading data from file then fuction return "" - # and error-text is in ERRNO(and no close-file action will be occured!). - # If reading data completed successfully then function try to close - # file and if while closing file some error occured then function - # returns "" and error-text is in ERRNO. - # Otherwise function returns readed data. - #_____________________________________________________________________________ - # - # fn _wrfile(_filepath,_data) - # - # Write data into file specified in _filepath. - # If _filepath=="" then no action occured and return "". - # Function write _data to file. No any changes in data occured. - # Function use _filerdne function internally. If some syntax error - # found in _filepath then function return "". - # If some error occured while writing data to file then fuction return "" - # and error-text is in ERRNO(and no close-file action will be occured!). - # If writing data completed successfully then function try to close - # file and if while closing file some error occured then function - # returns "" and error-text is in ERRNO. - # Otherwise function returns _filepath(re-processed). - #___________________________________________________________________________________ - # - # fn _filepath(_filepath) - # - # Return re-processed root-dir-name-ext of _filepath. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filerdne(_filepath) - # - # Return re-processed root-dir-filename of _filepath. - # If _filepath=="" then no action occured and return "". - # Function return result only if in _filepath present file-name(name - # and/or extension) - otherwise its return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filerdn(_filepath) - # - # Return re-processed root-dir-name of _filepath. - # If _filepath=="" then no action occured and return "". - # Function return result only if in _filepath present name field - - # - otherwise its return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filerd(_filepath) - # - # Return re-processed root-dir of _filepath. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filer(_filepath) - # - # Return re-processed root of _filepath. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filed(_filepath) - # - # Return re-processed dir of _filepath. - # If _filepath=="" then no action occured and return "". - # There is only one case when dir string can be =="" - when in - # _filepath specified unmounted drive(MS-format) and from- - # current-location address used(like Z:file.ext). In this - # case no rootdir-cache-record will be created. - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # fn _filene(_filepath) - # - # Return re-processed name-ext of _filepath. - # If _filepath=="" then no action occured and return "". - # Function return result only if in _filepath present file-name(name - # and/or extension) - otherwise its return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _filen(_filepath) - # - # Return re-processed name of _filepath. - # If _filepath=="" then no action occured and return "". - # Function return result only if in _filepath present name field - - # - otherwise its return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #_____________________________________________________________________________ - # - # fn _file(_filepath) - # - # Return re-processed ext of _filepath. - # If _filepath=="" then no action occured and return "". - # Function return result only if in _filepath present ext field - - # - otherwise its return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - #___________________________________________________________________________________ - # - # fn _dir(_ARR,_filepathmask) - # - # Get file-/folder-list of root-folder of _filepathmask. - # If _filepathmask=="" then no action occured and return "". - # _filepathmask can contain symbols like `*' and `?' as like - # its used in `dir'-shell command. - # Function gets file-/folder-list of specified root-dir-_filepathmask - # and return this list in array _ARR - where each element: - # - # index - is the _filepath of file-or-folder name-ext - # value - contains 3 fields separated by " ": - # 1. =="D" if this is folder - # ==/[0-9]+/ if this is file - size of file in bytes - # 2. ==date-of-creation of file or folder - # 3. ==time-of-creation of file or folder - # - # Function returns quantity of items in ARR. - #___________________________________________________________________________________ - # - # fn _filexist(_filepath) - # - # Test if file or path or drive specified in _filepath is exist. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - # Function returns _filepath if _filepath is exist. Otherwise - # function return 0. - #_____________________________________________________________________________ - # - # fn _filenotexist(_filepath) - # - # Test if file or path or drive specified in _filepath is not exist. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - # Function returns 1 if _filepath is not exist. Otherwise function - # return 0. - #_____________________________________________________________________________ - # - # fn _newdir(_filepath) - # - # Create path specified in root-dir-_filepath. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - # Function returns root-dir of _filepath. + return t #_______________________________________________________________________ - # - # fn _newdir(_filepath) - # - # Create path specified in root-dir-_filepath. If this folder - # already exist then it will be completely cleared. - # If _filepath=="" then no action occured and return "". - # If some syntax error found in _filepath then function return "" - # (and NO _filepath-cache-record will be created!). - # Function returns root-dir of _filepath. - #___________________________________________________________________________________ - # - # fn _getmpfile(_filepath,_currfilepath) - # - # Return .... - # - #_____________________________________________________________________________ - # - # fn _getmpdir(_filepath,_currfilepath) - # - # Return ... - # - #_____________________________________________________________________________ - # - # Temporary files folder. - # - # Temporary files folder location is defined by _FILEIO_TMPRD. - # If it wasn't been initialized before program run or not been initialized - # by ENVIRON["TMPDIR"] then it will defined as the: - # `current rootdir(stored in _FILEIO_RD)\programname.TMP' - # In this case if its already exist then it will completely cleared when _FILEIO - # library initialization processed. - # And at the program uninitialization processed it will completely - # cleared if _FILEIO_TMPCLRFLAG is true. - #___________________________________________________________________________________ - # - # var _FILEIO_RD (ENVIRON["CD"]) - # - # This var can be set before running program. It can contain path which - # will be used as default current dir while program run. - # If this var is set before program runs - then it will be refreshed by the - # _filerd it will be used as default current dir while program run. - # If this var is not set before program runs - then ENVIRON["CD"] can also - # set up default current dir while program run. If it set before program - # begin then it will be refreshed by the _filerd - and also writed into - # _FILEIO_RD. - # If both _FILEIO_RD and ENVIRON["CD"] are not set before program begins - # then real current root\dir will be writed into both _FILEIO_RD and - # ENVIRON["CD"] and it will be used as default current dir while program run. - # - #___________________________________________________________________________________ - # - # var _FILEIO_TMPRD (ENVIRON["TMPRD"]) - # - # This var can be set before running program. It can contain path which - # will be used as default temporary files root-folder while program run. - # If this var is set before program runs - then it will be refreshed by the - # _filerd - and also writed into ENVIRON["TMPRD"]. - # If this var is not set before program runs - then ENVIRON["TMPRD"] can also - # set up default temporary files root-folder while program run. If it set - # before program begin then it will be refreshed by the _filerd - and - # also writed into _FILEIO_TMPRD. - # If both _FILEIO_TMPRD and ENVIRON["TMPRD"] are not set before program begins - # then new folder into path specified by the _FILEIO_RD(after its handling) - # will be writed into both _FILEIO_TMPRD and ENVIRON["TMPRD"] and it - # will be used as default temporary files root-folder while program run. - #___________________________________________________________________________________ - # - # var _FILEPATH - # - # This var contain filepath of working script. It should be setting up externally. - # - # var _gawk_scriptlevel - #___________________________________________________________________________________ - #################################################################################### - ############################################################################### - if (_constatstrln > 0) { - _constat() - } - } - - - # Functions, listed alphabetically - - function W(p, p0, p1) - { - if (isarray(p0)) { - #_______________________________________________________________________ - ##################################################### - delete p0[p] - if (isarray(p1)) { - for (i in p1) { - if (isarray(p1[i])) { - p0[p][i][""] - delete p0[p][i][""] - _N_i0(p0[p][i], p1[i]) - } else { - p0[p][i] = p1[i] - } - } - return p - } - return (p0[p] = p1) - } - delete _[p][p0] - if (isarray(p1)) { - for (i in p1) { - if (isarray(p1[i])) { - _[p][p0][i][""] - delete _[p][p0][i][""] - _N_i0(_[p][p0][i], p1[i]) + + case "_lib_APPLY": + if (_errlog_errflkey) { + split(_errlog_errflkey, A, "") + for (a = 1; a in A; a++) { + if (A[a] == toupper(A[a])) { + b = 1 } else { - _[p][p0][i] = p1[i] + b = "" + } + switch (toupper(A[a])) { + case "T": + _ERRLOG_TF = b + break + case "V": + _ERRLOG_VF = b + break + case "I": + _ERRLOG_IF = b + break + case "W": + _ERRLOG_WF = b + break + case "E": + _ERRLOG_EF = b + break + case "F": + _ERRLOG_FF = b + break } } - return p + if (_ERRLOG_IF) { + _info("Log-message types inherited acc/deny: " "TRACE " ((_ERRLOG_TF ? "ON" : "OFF")) "/" "VERBOSE " ((_ERRLOG_VF ? "ON" : "OFF")) "/" "INFO " ((_ERRLOG_IF ? "ON" : "OFF")) "/" "WARNING " ((_ERRLOG_WF ? "ON" : "OFF")) "/" "ERROR " ((_ERRLOG_EF ? "ON" : "OFF")) "/" "FATAL " ((_ERRLOG_FF ? "ON" : "OFF"))) + } } - return (_[p][p0] = p1) + return + #_______________________________________________________________________ + + case "_lib_HELP": + return (_ln(" -L:TtVvIiWwEeFf - enable(upcase: TVIWEF) or disable(lowcase: tviwef) allowable type of") _ln(" log messages. Trace/Verbose/Informational/Warning/Error/Fatal.") _ln()) + #_______________________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_ERRLOG 1.0") + #_______________________________________________________________________ + + case "_lib_BEGIN": + P["_ERRLOG_TF"] = _ERRLOG_TF + P["_ERRLOG_VF"] = _ERRLOG_VF + P["_ERRLOG_IF"] = _ERRLOG_IF + P["_ERRLOG_WF"] = _ERRLOG_WF + P["_ERRLOG_EF"] = _ERRLOG_EF + P["_ERRLOG_FF"] = _ERRLOG_FF + P["_errlog_file"] = "/dev/stderr" + return } +} - function _ARR(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ########################################################## - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_ARR 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } +#______________________________________________________________________________________________ +function _EXIT() +{ + ################################################################################ + +} + +######################################################## + +function _EXTFN(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_EXTFN 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _BASE(c, t, P, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^((--([Vv])ersion)|(-([Vv])))[ \t]*/, A)) { - ########################################################## - t = substr(t, RLENGTH + 1) - _cmdln_version = A[3] A[5] +####################################################### + +function _FILEIO(c, t, P, A) +{ + switch (c) { + case "_lib_CMDLN": + if (match(t, /^[ \t]*-[Tt]([\+-])[ \t]*/, A)) { + t = substr(t, RLENGTH + 1) + if (A[1] == "+") { + _fileio_notdeltmpflag = 1 } else { - if (match(t, /^((-?\?)|(--help))[ \t]*/)) { - t = substr(t, RLENGTH + 1) - _cmdln_help = 1 - } else { - if (match(t, /^--[ \t]*/)) { - return _endpass(substr(t, RLENGTH + 1)) - } - } - } - #___________________________________________________________ - return t - case "_lib_APPLY": - if (_cmdln_help) { - match(_fbaccr(_LIBAPI, "_lib_HELP"), /^([^\x00]*)\x00([^\x01]*)\x01(.*)/, A) - _out(A[2] A[1] A[3]) - return _endpass(_basexit_fl = 1) + _fileio_notdeltmpflag = "" } - if (_cmdln_version) { - _out(_ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() ((_cmdln_version == "v" ? "" : _lib_NAMEVER()))) - return _endpass(_basexit_fl = 1) - } - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return ("\000" _ln(_PRODUCT_NAME " v" _PRODUCT_VERSION) _ln(_PRODUCT_COPYRIGHT) _ln() _ln(" Usage:") _ln() _ln(" " _PRODUCT_FILENAME " [/key1 /key2...] [-- cmdline]") _ln() _ln(" keys:") _ln() "\001" _ln(" -v -V --version - output product version and (if /V) all modules") _ln(" ? -? --help - output this help page") _ln(" -- - command line string edge")) - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_BASE 3.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return } - } - - function _DS(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - #____________________________________________________________________________ - ###################################################### - #___________________________________________________________ - #_____________________________________________________ - return t - case "_lib_APPLY": - #_____________________________________________________ - return - case "_lib_HELP": - #_____________________________________________________ - return (_ln() _ln(" Usage: " _PRODUCT_NAME " [/key1 /key2...] sourcefile [cmdline]") _ln()) - case "_lib_NAMEVER": - #_____________________________________________________ - return - case "_lib_BEGIN": - #_____________________________________________________ - return - case "_lib_END": - return + return t + #___________________________________________________________ + + case "_lib_APPLY": + if (_fileio_notdeltmpflag) { + _info("Temporary objects deletion DISABLED (inherited)") + } + return + #___________________________________________________________ + + case "_lib_HELP": + return (_ln(" -[Tt][+-] - inherited: +enable\\-disable temporary files\\dirs deletion") _ln()) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_FILEIO 2.1") + #___________________________________________________________ + + case "_lib_BEGIN": + P["ENVIRON"]["CD"] = ENVIRON["CD"] + P["_FILEIO_RD"] = _FILEIO_RD + P["_FILEIO_R"] = _FILEIO_R + P["_FILEIO_D"] = _FILEIO_D + if (! ("_FILEIO_TMPRD" in P)) { + P["_FILEIO_TMPRD"] = _getmpdir(_filen(P["SOURCE"]) "." ++_egawk_subcntr _CHR["SUBDIR"]) } + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _END() - { +############################################################ +#_____________________________________________________________________________ +function _FILEVER(c, t, P, a, A) +{ + ################################################# + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _ERRLOG(c, t, P, a, b, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^[ \t]*-L:([TtVvIiWwEeFf]*)[ \t]*/, A)) { - ######################################################## - t = substr(t, RLENGTH + 1) - _errlog_errflkey = _errlog_errflkey A[1] - } - #_______________________________________________________________________ - return t - case "_lib_APPLY": - if (_errlog_errflkey) { - split(_errlog_errflkey, A, "") - for (a = 1; a in A; a++) { - if (A[a] == toupper(A[a])) { - b = 1 - } else { - b = "" - } - switch (toupper(A[a])) { - case "T": - _ERRLOG_TF = b - break - case "V": - _ERRLOG_VF = b - break - case "I": - _ERRLOG_IF = b - break - case "W": - _ERRLOG_WF = b - break - case "E": - _ERRLOG_EF = b - break - case "F": - _ERRLOG_FF = b - break - } - } - if (_ERRLOG_IF) { - _info("Log-message types inherited acc/deny: " "TRACE " ((_ERRLOG_TF ? "ON" : "OFF")) "/" "VERBOSE " ((_ERRLOG_VF ? "ON" : "OFF")) "/" "INFO " ((_ERRLOG_IF ? "ON" : "OFF")) "/" "WARNING " ((_ERRLOG_WF ? "ON" : "OFF")) "/" "ERROR " ((_ERRLOG_EF ? "ON" : "OFF")) "/" "FATAL " ((_ERRLOG_FF ? "ON" : "OFF"))) - } - } - #_______________________________________________________________________ - return - case "_lib_HELP": - #_______________________________________________________________________ - return (_ln(" -L:TtVvIiWwEeFf - enable(upcase: TVIWEF) or disable(lowcase: tviwef) allowable type of") _ln(" log messages. Trace/Verbose/Informational/Warning/Error/Fatal.") _ln()) - case "_lib_NAMEVER": - #_______________________________________________________________________ - return _ln("_ERRLOG 1.0") - case "_lib_BEGIN": - P["_ERRLOG_TF"] = _ERRLOG_TF - P["_ERRLOG_VF"] = _ERRLOG_VF - P["_ERRLOG_IF"] = _ERRLOG_IF - P["_ERRLOG_WF"] = _ERRLOG_WF - P["_ERRLOG_EF"] = _ERRLOG_EF - P["_ERRLOG_FF"] = _ERRLOG_FF - P["_errlog_file"] = "/dev/stderr" - return - } +function _Foreach(A, f, p0, i) +{ + for (i in A) { + @f(A, i, p0) } +} - function _EXIT() - { - } +function _INIT(f) +{ +} - function _EXTFN(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ######################################################## - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_EXTFN 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } - } +#___________________________________________________________________________________ +function _INITBASE() +{ + ################################################################ + + _egawk_utilpath = ENVIRON["EGAWK_PATH"] "BIN\\UTIL\\" +} - function _FILEIO(c, t, P, A) - { - switch (c) { - case "_lib_CMDLN": - if (match(t, /^[ \t]*-[Tt]([\+-])[ \t]*/, A)) { - ####################################################### - t = substr(t, RLENGTH + 1) - if (A[1] == "+") { - _fileio_notdeltmpflag = 1 - } else { - _fileio_notdeltmpflag = "" - } - } - #___________________________________________________________ - return t - case "_lib_APPLY": - if (_fileio_notdeltmpflag) { - _info("Temporary objects deletion DISABLED (inherited)") - } - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return (_ln(" -[Tt][+-] - inherited: +enable\\-disable temporary files\\dirs deletion") _ln()) - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_FILEIO 2.1") - case "_lib_BEGIN": - P["ENVIRON"]["CD"] = ENVIRON["CD"] - P["_FILEIO_RD"] = _FILEIO_RD - P["_FILEIO_R"] = _FILEIO_R - P["_FILEIO_D"] = _FILEIO_D - if (! ("_FILEIO_TMPRD" in P)) { - P["_FILEIO_TMPRD"] = _getmpdir(_filen(P["SOURCE"]) "." ++_egawk_subcntr _CHR["SUBDIR"]) - } - #___________________________________________________________ - return - case "_lib_END": - return - } - } +###################################################### - function _FILEVER(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - ############################################################ - #_____________________________________________________________________________ - ################################################# - #___________________________________________________________ - #_____________________________________________________ - return t - case "_lib_APPLY": - #_____________________________________________________ - return - case "_lib_HELP": - #_____________________________________________________ - return - case "_lib_NAMEVER": - #_____________________________________________________ - return - case "_lib_BEGIN": - #_____________________________________________________ - return - case "_lib_END": - return - } +function _INSTRUC(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_INSTRUC 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } +} - function _Foreach(A, f, p0, i) - { - for (i in A) { - @f(A, i, p0) - } - } +#___________________________________________________________________________________ - function _INIT(f) - { - } - function _INITBASE() - { - #___________________________________________________________________________________ - ################################################################ - _egawk_utilpath = ENVIRON["EGAWK_PATH"] "BIN\\UTIL\\" - } +#################################################################################### - function _INSTRUC(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ###################################################### - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_INSTRUC 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } - } - function _N(F, v, p) - { - for (p in _UIDS) { - #___________________________________________________________________________________ - #################################################################################### - #_____________________________________________________________________________ - ########################################################### - delete _UIDS[p] - return _nN_i0(p, F, v) - } - return _nN_i0(_tgenuid(), F, v) +#_____________________________________________________________________________ +function _N(F, v, p) +{ + ########################################################### + for (p in _UIDS) { + delete _UIDS[p] + return _nN_i0(p, F, v) } + return _nN_i0(_tgenuid(), F, v) +} - function _SHORTCUT(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ##################################################### - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_shortcut 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } - } +##################################################### - function _START(t, i, A) - { - #______________________________________________________________________________________________ - ######################################################################### - _torexp_init() - test_uid() +function _SHORTCUT(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": return - _conl(patsplit("a,b,c", A, /[^,]/, B)) - test_splitstr() + #___________________________________________________________ + + case "_lib_HELP": return - A[""] - _CLASSPTR["ptr"] - ALTARR["ptra"] - _conl(_dumparr(SYMTAB)) - BB[1] = _NOP - zorr(1, 2, 3, 4, 5, 6) - zorr(BB, 1) - _rtn() - _rtn("") - _rtn(0) - _rtn("0") - _rtn(1) - _rtn("1") - _rtn(-1) - _rtn("-1") - _rtn("huj") - _rtn("ptr") - _rtn("ptra", ALTARR) - _rtn(ALTARR) - _rtn(ALTARR, ALTARR) + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_shortcut 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": return - _tstini() + #___________________________________________________________ + + case "_lib_END": return - # _split_regpath() - _splitpath_test() + } +} + +#______________________________________________________________________________________________ +function _START(t, i, A) +{ + ######################################################################### + _torexp_init() + test_uid() + return + _conl(patsplit("a,b,c", A, /[^,]/, B)) + test_splitstr() + return + A[""] + _CLASSPTR["ptr"] + ALTARR["ptra"] + _conl(_dumparr(SYMTAB)) + BB[1] = _NOP + zorr(1, 2, 3, 4, 5, 6) + zorr(BB, 1) + _rtn() + _rtn("") + _rtn(0) + _rtn("0") + _rtn(1) + _rtn("1") + _rtn(-1) + _rtn("-1") + _rtn("huj") + _rtn("ptr") + _rtn("ptra", ALTARR) + _rtn(ALTARR) + _rtn(ALTARR, ALTARR) + return + _tstini() + return + _splitpath_test() + # _split_regpath() + return + hh = "CPU" + _conl("go1!") + _conl(_var(_sharepath(hh, "gdfsgdsgsd sdgsdighjui teretiewrotrewut 345345345 rtjtireutireu huj"))) + _conl("go2!") + _conl(_var(_sharelist(AAA, hh), _dumparr(AAA))) + _conline() + A[1] = "h" + A[3] = "j" + t = "pizda" + if (match(t, /^pi(Z)da/, A)) { + _conl("match") + } else { + _conl("not match") + } + _conl(_dumparr(A)) + return + _pathSMA = "C:\\Program Files\\Altiris\\Altiris Agent\\" + DSPlugInPath = _pathSMA "Agents\\Deployment\\Agent\\" + DSAutoPath = _pathSMA + if (! _sysinfo(_SYS, _hostname)) { + _fatal("_sysinfo: unknown error") + } + _REG[""] + delete _REG[""] + _servoutput = _CHR["EOL"] _cmd("sc query state= all") + _dsbasepath = "\\\\CPU\\CPU\\DEV\\PROJECT\\_DS\\" + _rdreg(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris") + _wrfile("rego.txt", _dumparr(_REG)) + _conl("fF") + #_______________________________________________________________________ + + c = _getreg_i1(DDD, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\\204~.*\224Install path", _REG) + #_________________________________________________________________________________________ + pp = _n("NAME", "NS") + #pp=_n() + #___________________________________________________________________________________ + p = _defsolution(pp, "DS Plug-in", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") + ClientConfiguration = _defdll(p, "Client Configuration", "ClientConfiguration") + ClientImagingPrep = _defdll(p, "Client Inaging Preparation", "ClientImagingPrep") + ClientImaging = _defdll(p, "Client Imaging", "ClientImaging") + ClientPCT = _defdll(p, "Client PCT", "ClientPCT") + ClientRebootTo = _defdll(p, "Client Reboot To", "ClientRebootTo") + DeploymentAgent = _defdll(p, "Deployment Agent", "Deployment Agent") + DeploymentSolutionBaseAgent = _defdll(p, "Deployment Solution Base Agent", "Deployment Solution Base Agent") + ClientBCDEdit = _defile(p, "Client BCD Edit", "ClientBCDEdit.dll") + ClientCopyFile = _defile(p, "Client Copy File", "ClientCopyFile.dll") + ClientPreImage = _defile(p, "Client Pre Image", "ClientPreImage.dll") + ClientRebootTo = _defile(p, "Client Reboot To", "ClientRebootTo.dll") + _defile(p, "ConfigService.exe", "ConfigService.exe", "") + _defile(p, "config.dll", "config.dll", "") + _defsrv(p, "DS Plug-in Service", "Altiris Deployment Solution - System Configuration") + _defreg(p, "Deployment Agent Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR") + _defile(p, "Altiris_DeploymentSolutionAgent_7_1_x86.msi", (_SYS["OSArchitecture"] == "64-bit" ? "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{9D76E4CA-377A-472D-A82E-EDAD77E7E4ED}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x64.msi" : "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{4B747D25-612F-48FC-B6B5-9916D1BB755C}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x86.msi"), "") + _defdir(p, "Deployment Folder", a = gensub(/[^\\]*$/, "", 1, _rdsafe(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR", "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\Deployment\\Agent\\"))) + #___________________________________________________________________________________ + p = _defsolution(pp, "DS Auto", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") + _defdir(p, "C:\\Boot\\Altiris\\iso\\boot\\fonts\\", "C:\\Boot\\Altiris\\iso\\boot\\fonts\\") + _defdir(p, "C:\\Boot\\Altiris\\iso\\sources\\", "C:\\Boot\\Altiris\\iso\\sources\\") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.exe", "C:\\Boot\\Altiris\\iso\\autoinst.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.ini", "C:\\Boot\\Altiris\\iso\\autoinst.ini", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.exe", "C:\\Boot\\Altiris\\iso\\autoutil.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.ini", "C:\\Boot\\Altiris\\iso\\autoutil.ini", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bootmgr", "C:\\Boot\\Altiris\\iso\\bootmgr", "") + _defile(p, "C:\\Boot\\Altiris\\iso\\bootsect.exe", "C:\\Boot\\Altiris\\iso\\bootsect.exe", "") + _defreg(p, "Deployment Automation reg.File", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\File.XSZ", "autoutil.exe") + _defreg(p, "Deployment Automation reg.Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\Path.XSZ", "%systemdrive%\\boot\\altiris\\iso") + #_________________________________________________________________________________________ + + _check(pp) + #_________________________________________________________________________________________ + + _conl(_report(pp)) + _wrfile("report.txt", _report(pp)) +} + +######################################################### + +function _SYSIO(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": return - hh = "CPU" - _conl("go1!") - _conl(_var(_sharepath(hh, "gdfsgdsgsd sdgsdighjui teretiewrotrewut 345345345 rtjtireutireu huj"))) - _conl("go2!") - _conl(_var(_sharelist(AAA, hh), _dumparr(AAA))) - _conline() - A[1] = "h" - A[3] = "j" - t = "pizda" - if (match(t, /^pi(Z)da/, A)) { - _conl("match") - } else { - _conl("not match") - } - _conl(_dumparr(A)) + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_SYSIO 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": return - _pathSMA = "C:\\Program Files\\Altiris\\Altiris Agent\\" - DSPlugInPath = _pathSMA "Agents\\Deployment\\Agent\\" - DSAutoPath = _pathSMA - if (! _sysinfo(_SYS, _hostname)) { - _fatal("_sysinfo: unknown error") - } - _REG[""] - delete _REG[""] - _servoutput = _CHR["EOL"] _cmd("sc query state= all") - _dsbasepath = "\\\\CPU\\CPU\\DEV\\PROJECT\\_DS\\" - _rdreg(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris") - _wrfile("rego.txt", _dumparr(_REG)) - #_______________________________________________________________________ - _conl("fF") - #_________________________________________________________________________________________ - c = _getreg_i1(DDD, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\\204~.*\224Install path", _REG) - #pp=_n() - #___________________________________________________________________________________ - pp = _n("NAME", "NS") - p = _defsolution(pp, "DS Plug-in", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") - ClientConfiguration = _defdll(p, "Client Configuration", "ClientConfiguration") - ClientImagingPrep = _defdll(p, "Client Inaging Preparation", "ClientImagingPrep") - ClientImaging = _defdll(p, "Client Imaging", "ClientImaging") - ClientPCT = _defdll(p, "Client PCT", "ClientPCT") - ClientRebootTo = _defdll(p, "Client Reboot To", "ClientRebootTo") - DeploymentAgent = _defdll(p, "Deployment Agent", "Deployment Agent") - DeploymentSolutionBaseAgent = _defdll(p, "Deployment Solution Base Agent", "Deployment Solution Base Agent") - ClientBCDEdit = _defile(p, "Client BCD Edit", "ClientBCDEdit.dll") - ClientCopyFile = _defile(p, "Client Copy File", "ClientCopyFile.dll") - ClientPreImage = _defile(p, "Client Pre Image", "ClientPreImage.dll") - ClientRebootTo = _defile(p, "Client Reboot To", "ClientRebootTo.dll") - _defile(p, "ConfigService.exe", "ConfigService.exe", "") - _defile(p, "config.dll", "config.dll", "") - _defsrv(p, "DS Plug-in Service", "Altiris Deployment Solution - System Configuration") - _defreg(p, "Deployment Agent Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR") - _defile(p, "Altiris_DeploymentSolutionAgent_7_1_x86.msi", (_SYS["OSArchitecture"] == "64-bit" ? "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{9D76E4CA-377A-472D-A82E-EDAD77E7E4ED}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x64.msi" : "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{4B747D25-612F-48FC-B6B5-9916D1BB755C}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x86.msi"), "") - #___________________________________________________________________________________ - _defdir(p, "Deployment Folder", a = gensub(/[^\\]*$/, "", 1, _rdsafe(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR", "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\Deployment\\Agent\\"))) - p = _defsolution(pp, "DS Auto", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\") - _defdir(p, "C:\\Boot\\Altiris\\iso\\boot\\fonts\\", "C:\\Boot\\Altiris\\iso\\boot\\fonts\\") - _defdir(p, "C:\\Boot\\Altiris\\iso\\sources\\", "C:\\Boot\\Altiris\\iso\\sources\\") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.exe", "C:\\Boot\\Altiris\\iso\\autoinst.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.ini", "C:\\Boot\\Altiris\\iso\\autoinst.ini", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.exe", "C:\\Boot\\Altiris\\iso\\autoutil.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.ini", "C:\\Boot\\Altiris\\iso\\autoutil.ini", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bootmgr", "C:\\Boot\\Altiris\\iso\\bootmgr", "") - _defile(p, "C:\\Boot\\Altiris\\iso\\bootsect.exe", "C:\\Boot\\Altiris\\iso\\bootsect.exe", "") - _defreg(p, "Deployment Automation reg.File", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\File.XSZ", "autoutil.exe") - #_________________________________________________________________________________________ - _defreg(p, "Deployment Automation reg.Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\Path.XSZ", "%systemdrive%\\boot\\altiris\\iso") - #_________________________________________________________________________________________ - _check(pp) - _conl(_report(pp)) - _wrfile("report.txt", _report(pp)) - } - - function _SYSIO(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ######################################################### - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_SYSIO 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } } +} - function _W(p, A, v) - { - if (isarray(v)) { - if (p) { - #_______________________________________________________________________ - ######################################################################## - delete A[p] - A[p][""] - delete A[p][""] - _movarr(A[p], v) - } - return p - } +#_______________________________________________________________________ +######################################################################## + + +function _W(p, A, v) +{ + if (isarray(v)) { if (p) { delete A[p] - return (A[p] = v) + A[p][""] + delete A[p][""] + _movarr(A[p], v) } - return v + return p } - - function _Zexparr(S, s, t, i) - { - #_______________________________________________________________________ - ############################################## - t = "" - if (isarray(S)) { - for (i in S) { - t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) - } - } - if (s != "") { - gsub(/\x1B/, "\033;", s) - gsub(/\x10/, "\0330", s) - t = t "\021\021\020" s - } - gsub(/\x0A/, "\033:", t) - return t + if (p) { + delete A[p] + return (A[p] = v) } + return v +} - function _Zexparr_i0(S, t, i) - { +#_______________________________________________________________________ +function _Zexparr(S, s, t, i) +{ + ############################################## + t = "" + if (isarray(S)) { for (i in S) { - #_________________________________________________________________ t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) } - return t - } - - function _Zexparr_i1(t) - { - #_________________________________________________________________ - gsub(/\x1B/, "\033;", t) - gsub(/\x11/, "\0331", t) - gsub(/\x10/, "\0330", t) - return t } - - function _Zexparr_i2(t) - { - #_________________________________________________________________ - gsub(/\x10/, "\0330", t) + if (s != "") { + gsub(/\x1B/, "\033;", s) + gsub(/\x10/, "\0330", s) + t = t "\021\021\020" s + } + gsub(/\x0A/, "\033:", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i0(S, t, i) +{ + for (i in S) { + t = t ((isarray(S[i]) ? _Zexparr_i1(i) "\020" _Zexparr_i0(S[i]) "\021\021\020" : _Zexparr_i2(_Zexparr_i3(i) "\021" _Zexparr_i3(S[i])) "\020")) + } + return t +} + +#_________________________________________________________________ +function _Zexparr_i1(t) +{ + gsub(/\x1B/, "\033;", t) + gsub(/\x11/, "\0331", t) + gsub(/\x10/, "\0330", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i2(t) +{ + gsub(/\x10/, "\0330", t) + return t +} + +#_________________________________________________________________ +function _Zexparr_i3(t) +{ + gsub(/\x1B/, "\033;", t) + gsub(/\x11/, "\0331", t) + return t +} + +#_______________________________________________________________________ +function _Zimparr(D, t, A, B) +{ + ############################################## + if (isarray(D)) { + split(t, A, /\x10/, B) + t = _Zimparr_i0(A, B, _Zimparr_i1(D, A, B, 1)) + gsub(/\x1B\x30/, "\020", t) + gsub(/\x1B\x3B/, "\033", t) return t } +} - function _Zexparr_i3(t) - { - #_________________________________________________________________ - gsub(/\x1B/, "\033;", t) - gsub(/\x11/, "\0331", t) - return t - } +#_________________________________________________________________ +function _Zimparr_i0(A, B, i) +{ + return ((i in A ? A[i] B[i] _Zimparr_i0(A, B, i + 1) : "")) +} - function _Zimparr(D, t, A, B) - { - if (isarray(D)) { - #_______________________________________________________________________ - ############################################## - split(t, A, /\x10/, B) - t = _Zimparr_i0(A, B, _Zimparr_i1(D, A, B, 1)) - gsub(/\x1B\x30/, "\020", t) - gsub(/\x1B\x3B/, "\033", t) - return t +#_________________________________________________________________ +function _Zimparr_i1(D, A, B, i, t, a, n) +{ + while (i in B) { + if ((t = A[i++]) == "\021\021") { + return i } - } - - function _Zimparr_i0(A, B, i) - { - #_________________________________________________________________ - return ((i in A ? A[i] B[i] _Zimparr_i0(A, B, i + 1) : "")) - } - - function _Zimparr_i1(D, A, B, i, t, a, n) - { - while (i in B) { - #_________________________________________________________________ - if ((t = A[i++]) == "\021\021") { - return i + gsub(/\x1B\x30/, "\020", t) + if ((a = index(t, "\021")) > 0) { + if (isarray(D[n = _Zimparr_i2(substr(t, 1, a - 1))])) { + delete D[n] } - gsub(/\x1B\x30/, "\020", t) - if ((a = index(t, "\021")) > 0) { - if (isarray(D[n = _Zimparr_i2(substr(t, 1, a - 1))])) { - delete D[n] - } - D[n] = _Zimparr_i2(substr(t, a + 1)) + D[n] = _Zimparr_i2(substr(t, a + 1)) + } else { + if (! isarray(D[t = _Zimparr_i2(t)])) { + delete D[t] + D[t][""] + delete D[t][""] + } + i = _Zimparr_i1(D[t], A, B, i) + } + } +} + +#_________________________________________________________________ +function _Zimparr_i2(t) +{ + gsub(/\x1B\x31/, "\021", t) + gsub(/\x1B\x3B/, "\033", t) + return t +} + +#_____________________________________________________________________________ +function _Zimport(t, p, A, c, i, n, B) +{ + ############################################## + if (p) { + c = split(t, B, /\x0A/) + for (i = 1; i <= c; i++) { + if ((t = B[i]) == "") { + continue + } + gsub(/\x1B\x3A/, "\n", t) + if (match(t, /^_ERRLOG: /)) { + _tLOG[n = _wLCHLD(p, _N())][""] + delete _tLOG[n][""] + _Zimparr(_tLOG[n], substr(t, 10)) } else { - if (! isarray(D[t = _Zimparr_i2(t)])) { - delete D[t] - D[t][""] - delete D[t][""] + if ((t = _pass(_IMPORT, t, p, A)) != "") { + gsub(/\x1B\x3B/, "\033", t) + _wLCHLD(p, _N(_tSTR, t)) } - i = _Zimparr_i1(D[t], A, B, i) } } - } - - function _Zimparr_i2(t) - { - #_________________________________________________________________ - gsub(/\x1B\x31/, "\021", t) - gsub(/\x1B\x3B/, "\033", t) - return t - } - - function _Zimport(t, p, A, c, i, n, B) - { - if (p) { - #_____________________________________________________________________________ - ############################################## - c = split(t, B, /\x0A/) - for (i = 1; i <= c; i++) { - if ((t = B[i]) == "") { - continue - } - gsub(/\x1B\x3A/, "\n", t) - if (match(t, /^_ERRLOG: /)) { - _tLOG[n = _wLCHLD(p, _N())][""] - delete _tLOG[n][""] - _Zimparr(_tLOG[n], substr(t, 10)) + return p + } else { + _expout(t) + } +} + +function _acc(A, a, t) +{ + if (t) { + if (_VLDMAXSTRING < length(t) + length(a)) { + if (a) { + if (_VLDMAXSTRING < length(t)) { + A[--A[_ARRPTR]] = a + A[--A[_ARRPTR]] = t } else { - if ((t = _pass(_IMPORT, t, p, A)) != "") { - gsub(/\x1B\x3B/, "\033", t) - _wLCHLD(p, _N(_tSTR, t)) - } + A[--A[_ARRPTR]] = a t } + } else { + A[++A[_ARRLEN]] = t } - return p - } else { - _expout(t) + return "" } + return (a t) } + return a +} - function _acc(A, a, t) - { - if (t) { - if (_VLDMAXSTRING < length(t) + length(a)) { - if (a) { - if (_VLDMAXSTRING < length(t)) { - A[--A[_ARRPTR]] = a - A[--A[_ARRPTR]] = t - } else { - A[--A[_ARRPTR]] = a t - } - } else { - A[++A[_ARRLEN]] = t - } - return "" - } - return (a t) - } - return a +function _accmpu(A, a, n) +{ + if (n) { + return (_mpufn0 = n) } - - function _accmpu(A, a, n) - { - if (n) { - return (_mpufn0 = n) - } - if (_mpuacc) { - if (_VLDMAXSTRING < length(_mpuacc) + length(a)) { - if (a) { - if (_VLDMAXSTRING < length(_mpuacc)) { - A[--A[_ARRLEN]] = a - A[--A[_ARRLEN]] = _mpuacc - } else { - A[--A[_ARRLEN]] = a _mpuacc - } - } else { + if (_mpuacc) { + if (_VLDMAXSTRING < length(_mpuacc) + length(a)) { + if (a) { + if (_VLDMAXSTRING < length(_mpuacc)) { + A[--A[_ARRLEN]] = a A[--A[_ARRLEN]] = _mpuacc + } else { + A[--A[_ARRLEN]] = a _mpuacc } - _mpuacc = "" } else { - _mpuacc = a _mpuacc + A[--A[_ARRLEN]] = _mpuacc } + _mpuacc = "" } else { - _mpuacc = a + _mpuacc = a _mpuacc } + } else { + _mpuacc = a } +} - function _add(S, sf, D, df) - { - if (sf in S) { - if (isarray(S[sf])) { - if (df in D) { - #_______________________________________________________________________ - ################################################ - if (isarray(D[df])) { - return _extarr(D[df], S[sf]) - } - delete D[df] - } - D[df][""] - delete D[df][""] - return _extarr(D[df], S[sf]) - } else { +#_______________________________________________________________________ +function _add(S, sf, D, df) +{ + ################################################ + if (sf in S) { + if (isarray(S[sf])) { + if (df in D) { if (isarray(D[df])) { - delete D[df] + return _extarr(D[df], S[sf]) } - D[df] = D[df] S[sf] + delete D[df] } + D[df][""] + delete D[df][""] + return _extarr(D[df], S[sf]) + } else { + if (isarray(D[df])) { + delete D[df] + } + D[df] = D[df] S[sf] } } +} - function _addarr(D, S) - { - #_________________________________________________________________ - ############################################# - if (isarray(S)) { - _addarr_i0(D, S) - } - } - - function _addarr_i0(D, S, i) - { - for (i in S) { - if (isarray(S[i])) { - #_____________________________________________________ - delete D[i] - D[i][""] - delete D[i][""] - _addarr_i0(D[i], S[i]) - } else { - delete D[i] - D[i] = S[i] - } - } +#_________________________________________________________________ +function _addarr(D, S) +{ + ############################################# + if (isarray(S)) { + _addarr_i0(D, S) } +} - function _addarrmask(D, S, M) - { - for (_addarrmaski0 in M) { - if (_addarrmaski0 in S) { - if (isarray(S[_addarrmaski0])) { - if (! isarray(D[_addarrmaski0])) { - #_______________________________________________________________________ - ############################################# - delete D[_addarrmaski0] - D[_addarrmaski0][""] - delete D[_addarrmaski0][""] - } - if (isarray(M[_addarrmaski0])) { - _addarrmask(D[_addarrmaski0], S[_addarrmaski0], M[_addarrmaski0]) - } else { - _extarr_i0(D[_addarrmaski0], S[_addarrmaski0]) - } +#_____________________________________________________ +function _addarr_i0(D, S, i) +{ + for (i in S) { + if (isarray(S[i])) { + delete D[i] + D[i][""] + delete D[i][""] + _addarr_i0(D[i], S[i]) + } else { + delete D[i] + D[i] = S[i] + } + } +} + +#_______________________________________________________________________ +function _addarrmask(D, S, M) +{ + ############################################# + for (_addarrmaski0 in M) { + if (_addarrmaski0 in S) { + if (isarray(S[_addarrmaski0])) { + if (! isarray(D[_addarrmaski0])) { + delete D[_addarrmaski0] + D[_addarrmaski0][""] + delete D[_addarrmaski0][""] + } + if (isarray(M[_addarrmaski0])) { + _addarrmask(D[_addarrmaski0], S[_addarrmaski0], M[_addarrmaski0]) } else { - if (isarray(D[_addarrmaski0])) { - delete D[_addarrmaski0] - } - D[_addarrmaski0] = S[_addarrmaski0] + _extarr_i0(D[_addarrmaski0], S[_addarrmaski0]) } } else { - delete D[_addarrmaski0] + if (isarray(D[_addarrmaski0])) { + delete D[_addarrmaski0] + } + D[_addarrmaski0] = S[_addarrmaski0] } + } else { + delete D[_addarrmaski0] } } +} - function _addf(A, f) - { - #___________________________________________________________________________________ - #################################################################################### - #_______________________________________________________________________ - ##################################################### - A["B"][""] = A["F"][A["B"][f] = A["B"][""]] = f - } +#___________________________________________________________________________________ +#################################################################################### - function _addfile(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - #___________________________________________________________ - ################################## - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" - ERRNO = "" - print(d) >> f - if (ERRNO) { - return "" - } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" - } - return d - } - function _addlib(f) - { - #_____________________________________________________________________________ - ########################################################### - _addf(_LIBAPI, f) - } +#_______________________________________________________________________ +function _addf(A, f) +{ + ##################################################### + A["B"][""] = A["F"][A["B"][f] = A["B"][""]] = f +} - function _addlist(A, v) - { - #___________________________________________________________________________________ - #################################################################################### - #_______________________________________________________________________ - ################################################## - A[++A[0]] = v +#___________________________________________________________ +function _addfile(f, d, a, b) +{ + ################################## + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function _bearray(A) - { - ############################## - #_______________________________________________________________________ - ############################################ - #_______________________________________________________________________ - #################################################### - if (isarray(A) || A == 0 && A == "") { - return 1 - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) >> f + if (ERRNO) { + return "" } - - function _bframe(A, t, p) - { - #_________________________________________________________________ - ########################################### - return _bframe_i0(A, t, p, A[""]) + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" } - - function _bframe_i0(A, t, p, f) - { - #___________________________________________________________ - return ((f ? _bframe_i0(A, t, p, A[f]) (@f(t, p)) : "")) + return d +} + +#_____________________________________________________________________________ +function _addlib(f) +{ + ########################################################### + _addf(_LIBAPI, f) +} + +#___________________________________________________________________________________ +#################################################################################### + + +#_______________________________________________________________________ +function _addlist(A, v) +{ + ################################################## + A[++A[0]] = v +} + +############################################ +#_______________________________________________________________________ +function _bearray(A) +{ + #################################################### + if (isarray(A) || A == 0 && A == "") { + return 1 } +} - function _cfguid(p, optr, pfx, sfx, hstrcnt, lstrchr) - { - # add to _dumparr: checking that if element is undefined - #_______________________________________________________________________ - #################### 0 # - delete _UIDOBL[p] - if (_isptr(optr)) { - if (optr == p) { - delete _UIDOBLV[p] - delete _UIDOBLV[_UIDOBLV[_UIDOBL[p] = p][""] = p][""] - } else { - if (optr in _UIDOBL) { - _UIDOBL[p] = _UIDOBL[optr] - } - } - } - _UIDPFX[p] = (_istr(pfx) ? pfx : "") - _UIDSFX[p] = (_istr(sfx) ? sfx : "") - if (_isptr(hstrcnt)) { - if (hstrcnt != p) { - _UIDCHR[p] = _UIDCHR[_UIDCNT[p] = _UIDCNT[hstrcnt]] - return p - } - hstrcnt = _NOP - } - _UIDCNTL[_UIDCNT[p] = p] = _cfguidchr(p, hstrcnt, lstrchr) - return p - } +#_________________________________________________________________ +function _bframe(A, t, p) +{ + ########################################### + return _bframe_i0(A, t, p, A[""]) +} - function _cfguidchr(p, h, l, H, L) - { - if (_isptr(l)) { - #_____________________________________________________ - if (l != p) { - return (_UIDCHR[p] = _UIDCHR[l]) - } - _UIDCHR[p] = p - l = _NOP - } - _UIDCHR[p] = p - _splitstr(H, h, _UIDCHRH[_classys]) - _splitstr(L, l, H) - delete _UIDCHRH[_UIDCHRH[p][""] = p][""] - delete _UIDCHRL[_UIDCHRL[p][""] = p][""] - _cfguidh(p, H, L) - return _cfguidl(p, L, L) - } - - function _cfguidh(p, H, L, hi, h, li) - { - for (hi = 1; hi in H; hi++) { - #_______________________________________________ - h = H[hi] - for (li = 1; li in L; li++) { - _UIDCHRH[p][h L[li]] - } - } - } +#___________________________________________________________ +function _bframe_i0(A, t, p, f) +{ + return ((f ? _bframe_i0(A, t, p, A[f]) (@f(t, p)) : "")) +} - function _cfguidl(p, H, L, hi, h, hl, li) - { - for (hi = 1; hi in H; hi++) { - h = H[hi] - for (li = 1; li in L; li++) { - hl = _UIDCHRL[p][hl] = h L[li] - } - } - return hl - } +# add to _dumparr: checking that if element is undefined - function _check(p) - { - #______________________________________________________________________________________________ - ################################################################################# - #______________________________________________________________________________________________ - ################################################################################ - #____________________________________________________________________________________________________ - #################################################################################### - _dll_check(p) - _file_check(p) - _serv_check(p) - _reg_check(p) - } - function _chrline(t, ts, w, s) - { - #_______________________________________________________________________ - ############################################# - return ((t = " " _tabtospc(t, ts) ((t ? (t ~ /[ \t]$/ ? "" : " ") : ""))) _getchrln((s ? s : "_"), ((w ? w : _CON_WIDTH - 1)) - length(t)) _CHR["EOL"]) - } - function _cmd(c, i, A) - { - #_____________________________________________________________________________ - ####################################################### - _fio_cmda = RS - RS = ".{1,}" - _fio_cmdb = BINMODE - BINMODE = "rw" - ERRNO = RT = _NUL - c | getline RS - BINMODE = _fio_cmdb - RS = _fio_cmda - if (ERRNO || 0 > (_exitcode = close(c))) { - return (RT = _NOP) - } - return RT - } - function _cmparr(A0, A1, R, a, i) - { - #_______________________________________________________________________ - ########################################## - a = 0 - delete R - for (i in A0) { - if (! (i in A1)) { - a++ - R[i] = 0 - } else { - if (A0[i] != A1[i]) { - a++ - R[i] = 2 - } - } - } - for (i in A1) { - if (! (i in A0)) { - a++ - R[i] = 1 - } - } - return a - } - function _con(t, ts, a, b, c, d, i, r, A, B) - { - #_____________________________________________________________________________ - ########################################## - d = RLENGTH - if ((c = split(r = t, A, /\x0D?\x0A/, B)) > 0) { - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - if (c > 1) { - if ((i = length(t = _tabtospc(A[1], ts, _conlastrln))) < _constatstrln) { - t = t _getchrln(" ", _constatstrln - i) - } - print(t B[1]) > _SYS_STDCON - for (i = 2; i < c; i++) { - print(_tabtospc(A[i], ts) B[i]) > _SYS_STDCON - } - print(_conlastr = _tabtospc(A[c], ts)) > _SYS_STDCON - fflush(_SYS_STDCON) - } else { - print(t = _tabtospc(t, ts, _conlastrln)) > _SYS_STDCON - fflush(_SYS_STDCON) - _conlastr = _conlastr t - } - if ((i = length(_conlastr)) >= _CON_WIDTH) { - _conlastr = substr(_conlastr, 1 + int(i / _CON_WIDTH) * _CON_WIDTH) - } - _conlastrln = length(_conlastr) - if (_constatstr) { - print((t = _constatgtstr(_constatstr, _CON_WIDTH - 1 - _conlastrln)) _CHR["CR"] _conlastr) > _SYS_STDCON - fflush(_SYS_STDCON) - _constatstrln = length(t) - } - BINMODE = a - ORS = b - RLENGTH = d - return r - } - RLENGTH = d - } - function _conin(t, a, b) - { - #_______________________________________________________________________ - ################################################# - _constatpush() - _constat() - a = BINMODE - b = RS - BINMODE = "rw" - RS = "\n" - _con(t) - getline t < "CON" - close("CON") - _conlastrln = 0 - _conlastr = "" - gsub(/[\x0D\x0A]+/, "", t) - BINMODE = a - RS = b - _constatpop() - return t - } - function _conl(t, ts) - { - #_______________________________________________________________________ - #################################################### - return _con(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"])), ts) - } - function _conline(t, ts) - { - #_______________________________________________________________________ - ################################################# - return _con(_chrline(t, ts)) - } - function _conlq(t, ts) - { - #___________________________________________________________________________________ - #################################################################################### - return _conl("`" t "'", ts) - } - function _constat(t, ts, ln, a) - { - if (_constatstrln > (ln = length(t = _constatgtstr(_constatstr = _tabtospc(t, ts), _CON_WIDTH - 1 - _conlastrln)))) { - #_______________________________________________________________________ - ########################################### - t = t _getchrln(" ", _constatstrln - ln) - } - _constatstrln = ln - ln = ORS - a = BINMODE - BINMODE = "rw" - ORS = "" - print(t _CHR["CR"] _conlastr) > _SYS_STDCON - fflush(_SYS_STDCON) - ORS = ln - BINMODE = a - return _constatstr - } - function _constatgtstr(t, ln, a, b) - { - if (ln < 1) { - #_________________________________________________________________ - return "" - } - if ((a = length(t)) <= ln) { - return t - } - if (ln < 11) { - return substr(t, a - ln + 1) - } - if (ln < 19) { - return ("..." substr(t, a - ln + 4)) - } - return (substr(t, 1, b = int((ln - 3) / 2)) "..." substr(t, a - ln + b + 4)) - } - function _constatpop() - { - if (_CONSTATPUSH[0] > 0) { - #_______________________________________________________________________ - ################################################## - return _constat(_CONSTATPUSH[_CONSTATPUSH[0]--]) - } - return _constat("") - } - function _constatpush(t, ts) - { - #_______________________________________________________________________ - ############################################# - _CONSTATPUSH[++_CONSTATPUSH[0]] = _constatstr - if (t) { - _constat(t, ts) - } - return _constatstr - } - function _creport(p, t, f, z) - { - #___________________________________________________________________________________ - _[p]["REPORT"] = _[p]["REPORT"] _ln(t ((f == "" ? "" : ": " f))) - } - function _defdir(pp, n, f, v, p) - { - #_________________________________________________________________________________________ - ############################################################# - _[p = _wLCHLD(pp, _n("TYPE", "defdir"))]["NAME"] = n - _[p]["DIR"] = f - return p - } - function _defdll(pp, n, rn, p) - { - #_________________________________________________________________________________________ - ############################################################## - _[p = _wLCHLD(pp, _n("TYPE", "defdll"))]["NAME"] = n - _[p]["REGPATH"] = _[pp]["REGPATH"] rn - _[p]["ERRHOST"] = pp - return p - } - function _defescarr(D, r, S, i, c, t) - { - if (isarray(S)) { - for (i = 0; i < 256; i++) { - if ((c = _CHR[i]) ~ r) { - #___________________________________________________________ - D[c] = "\\" S[c] - t = t c - } else { - if (D[c] == "") { - D[c] = c - } - } - } + +#_______________________________________________________________________ +function _cfguid(p, optr, pfx, sfx, hstrcnt, lstrchr) +{ + #################### 0 # + delete _UIDOBL[p] + if (_isptr(optr)) { + if (optr == p) { + delete _UIDOBLV[p] + delete _UIDOBLV[_UIDOBLV[_UIDOBL[p] = p][""] = p][""] } else { - for (i = 0; i < 256; i++) { - if ((c = _CHR[i]) ~ r) { - D[c] = S c - if (S != "") { - t = t c - } - } else { - if (D[c] == "") { - D[c] = c - } - } + if (optr in _UIDOBL) { + _UIDOBL[p] = _UIDOBL[optr] } } - return t } - - function _defile(pp, n, f, v, p) - { - #_________________________________________________________________________________________ - ############################################################# - _[p = _wLCHLD(pp, _n("TYPE", "defile"))]["NAME"] = n - _[p]["FILE"] = f - if (! (v == 0 && v == "")) { - _[p]["RQVERSION"] = v + _UIDPFX[p] = (_istr(pfx) ? pfx : "") + _UIDSFX[p] = (_istr(sfx) ? sfx : "") + if (_isptr(hstrcnt)) { + if (hstrcnt != p) { + _UIDCHR[p] = _UIDCHR[_UIDCNT[p] = _UIDCNT[hstrcnt]] + return p } - return p + hstrcnt = _NOP } + _UIDCNTL[_UIDCNT[p] = p] = _cfguidchr(p, hstrcnt, lstrchr) + return p +} - function _defn(f, c, v) - { - #_______________________________________________________________________ - ################################################### - FUNCTAB[c f] = v - } - - function _defreg(pp, n, f, v, p) - { - #_________________________________________________________________________________________ - ############################################################# - _[p = _wLCHLD(pp, _n("TYPE", "defreg"))]["NAME"] = n - _[p]["REGPATH"] = f - if (! (v == 0 && v == "")) { - _[p]["VALUE"] = v +#_____________________________________________________ +function _cfguidchr(p, h, l, H, L) +{ + if (_isptr(l)) { + if (l != p) { + return (_UIDCHR[p] = _UIDCHR[l]) } + _UIDCHR[p] = p + l = _NOP + } + _UIDCHR[p] = p + _splitstr(H, h, _UIDCHRH[_classys]) + _splitstr(L, l, H) + delete _UIDCHRH[_UIDCHRH[p][""] = p][""] + delete _UIDCHRL[_UIDCHRL[p][""] = p][""] + _cfguidh(p, H, L) + return _cfguidl(p, L, L) +} + +#_______________________________________________ +function _cfguidh(p, H, L, hi, h, li) +{ + for (hi = 1; hi in H; hi++) { + h = H[hi] + for (li = 1; li in L; li++) { + _UIDCHRH[p][h L[li]] + } + } +} + +function _cfguidl(p, H, L, hi, h, hl, li) +{ + for (hi = 1; hi in H; hi++) { + h = H[hi] + for (li = 1; li in L; li++) { + hl = _UIDCHRL[p][hl] = h L[li] + } + } + return hl +} + +#____________________________________________________________________________________________________ +function _check(p) +{ + #################################################################################### + _dll_check(p) + _file_check(p) + _serv_check(p) + _reg_check(p) +} + +#_______________________________________________________________________ +function _chrline(t, ts, w, s) +{ + ############################################# + return ((t = " " _tabtospc(t, ts) ((t ? (t ~ /[ \t]$/ ? "" : " ") : ""))) _getchrln((s ? s : "_"), ((w ? w : _CON_WIDTH - 1)) - length(t)) _CHR["EOL"]) +} + +#_____________________________________________________________________________ +function _cmd(c, i, A) +{ + ####################################################### + _fio_cmda = RS + RS = ".{1,}" + _fio_cmdb = BINMODE + BINMODE = "rw" + ERRNO = RT = _NUL + c | getline RS + BINMODE = _fio_cmdb + RS = _fio_cmda + if (ERRNO || 0 > (_exitcode = close(c))) { + return (RT = _NOP) } - - function _defsolution(pp, n, rn, p) - { - #_______________________________________________________________________________________________ - ############################################################### - _[p = _wLCHLD(pp, _n("TYPE", "solution"))]["NAME"] = n - _[p]["REGPATH"] = rn - _[p]["ERRHOST"] = pp - return p - } - - function _defsrv(pp, n, f, v, p) - { - #_________________________________________________________________________________________ - ############################################################# - _[p = _wLCHLD(pp, _n("TYPE", "defsrv"))]["NAME"] = n - _[p]["SERVNAME"] = f - return p - } - - function _del(f, c, a, A) - { - if (match(f, /\\[ \t]*$/)) { - if ((c = toupper(_filerd(f))) && length(f) == FLENGTH) { - #_______________________________________________________________________ - ################################################# - _cmd("rd " c " /S /Q 2>NUL") - _deletepfx(_WFILEROOTDIR, c) - _deletepfx(_FILEIO_RDTMP, c) - _deletepfx(_FILEIO_RDNETMP, c) - } else { - _conl("HUJ TEBE!") - return "" - } + return RT +} + +#_______________________________________________________________________ +function _cmparr(A0, A1, R, a, i) +{ + ########################################## + a = 0 + delete R + for (i in A0) { + if (! (i in A1)) { + a++ + R[i] = 0 } else { - a = _dir(A, f) - _cmd("del " f " /Q 2>NUL") - for (c in A) { - if (c ~ /\\$/) { - _cmd("rd " c " /S /Q 2>NUL") - _deletepfx(_WFILEROOTDIR, c) - _deletepfx(_FILEIO_RDTMP, c) - } - _deletepfx(_FILEIO_RDNETMP, c) + if (A0[i] != A1[i]) { + a++ + R[i] = 2 } } - return a } - - function _delay(t, a) - { - for (a = 1; a <= t; a++) { - #_______________________________________________________________________ - ################################################### - _delayms() - } - } - - function _delayms(a) - { - #_________________________________________________________________ - ############################################# - for (a = 1; a <= _delay_perfmsdelay; a++) { + for (i in A1) { + if (! (i in A0)) { + a++ + R[i] = 1 } } + return a +} - function _deletepfx(A, f, B, le, i) - { - #_______________________________________________________________________ - ######################################## - le = length(f) - for (i in A) { - if (substr(toupper(i), 1, le) == f) { - B[i] = A[i] - delete A[i] +#_____________________________________________________________________________ +function _con(t, ts, a, b, c, d, i, r, A, B) +{ + ########################################## + d = RLENGTH + if ((c = split(r = t, A, /\x0D?\x0A/, B)) > 0) { + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + if (c > 1) { + if ((i = length(t = _tabtospc(A[1], ts, _conlastrln))) < _constatstrln) { + t = t _getchrln(" ", _constatstrln - i) + } + print(t B[1]) > _SYS_STDCON + for (i = 2; i < c; i++) { + print(_tabtospc(A[i], ts) B[i]) > _SYS_STDCON } + print(_conlastr = _tabtospc(A[c], ts)) > _SYS_STDCON + fflush(_SYS_STDCON) + } else { + print(t = _tabtospc(t, ts, _conlastrln)) > _SYS_STDCON + fflush(_SYS_STDCON) + _conlastr = _conlastr t + } + if ((i = length(_conlastr)) >= _CON_WIDTH) { + _conlastr = substr(_conlastr, 1 + int(i / _CON_WIDTH) * _CON_WIDTH) + } + _conlastrln = length(_conlastr) + if (_constatstr) { + print((t = _constatgtstr(_constatstr, _CON_WIDTH - 1 - _conlastrln)) _CHR["CR"] _conlastr) > _SYS_STDCON + fflush(_SYS_STDCON) + _constatstrln = length(t) } + BINMODE = a + ORS = b + RLENGTH = d + return r } - - function _delf(A, f) - { - #_________________________________________________________________ - ############################################### - A["B"][A["F"][A["B"][f]] = A["F"][f]] = A["B"][f] - delete A["F"][f] - delete A["B"][f] + RLENGTH = d +} + +#_______________________________________________________________________ +function _conin(t, a, b) +{ + ################################################# + _constatpush() + _constat() + a = BINMODE + b = RS + BINMODE = "rw" + RS = "\n" + _con(t) + getline t < "CON" + close("CON") + _conlastrln = 0 + _conlastr = "" + gsub(/[\x0D\x0A]+/, "", t) + BINMODE = a + RS = b + _constatpop() + return t +} + +#_______________________________________________________________________ +function _conl(t, ts) +{ + #################################################### + return _con(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"])), ts) +} + +#_______________________________________________________________________ +function _conline(t, ts) +{ + ################################################# + return _con(_chrline(t, ts)) +} + +#___________________________________________________________________________________ +#################################################################################### + + + +function _conlq(t, ts) +{ + return _conl("`" t "'", ts) +} + +#_______________________________________________________________________ +function _constat(t, ts, ln, a) +{ + ########################################### + if (_constatstrln > (ln = length(t = _constatgtstr(_constatstr = _tabtospc(t, ts), _CON_WIDTH - 1 - _conlastrln)))) { + t = t _getchrln(" ", _constatstrln - ln) + } + _constatstrln = ln + ln = ORS + a = BINMODE + BINMODE = "rw" + ORS = "" + print(t _CHR["CR"] _conlastr) > _SYS_STDCON + fflush(_SYS_STDCON) + ORS = ln + BINMODE = a + return _constatstr +} + +#_________________________________________________________________ +function _constatgtstr(t, ln, a, b) +{ + if (ln < 1) { + return "" } - - function _deluid(p) - { - if (p in _CLASSPTR) { - #_______________________________________________________________________ - ################################################# 1 # - _deluida0 = _CLASSPTR[p] - if (_deluida0 in _UIDOBL) { - _UIDOBLV[_UIDOBL[_deluida0]][p] - } - } - delete _CLASSPTR[p] - return _deluida0 + if ((a = length(t)) <= ln) { + return t } - - function _dir(A, rd, i, r, f, ds, pf, B, C) - { - #_______________________________________________________________________ - #################################### - delete A - gsub(/(^[ \t]*)|([ \t]*$)/, "", rd) - if (rd == "") { - return "" + if (ln < 11) { + return substr(t, a - ln + 1) + } + if (ln < 19) { + return ("..." substr(t, a - ln + 4)) + } + return (substr(t, 1, b = int((ln - 3) / 2)) "..." substr(t, a - ln + b + 4)) +} + +#_______________________________________________________________________ +function _constatpop() +{ + ################################################## + if (_CONSTATPUSH[0] > 0) { + return _constat(_CONSTATPUSH[_CONSTATPUSH[0]--]) + } + return _constat("") +} + +#_______________________________________________________________________ +function _constatpush(t, ts) +{ + ############################################# + _CONSTATPUSH[++_CONSTATPUSH[0]] = _constatstr + if (t) { + _constat(t, ts) + } + return _constatstr +} + +#___________________________________________________________________________________ +function _creport(p, t, f, z) +{ + _[p]["REPORT"] = _[p]["REPORT"] _ln(t ((f == "" ? "" : ": " f))) +} + +#_________________________________________________________________________________________ +function _defdir(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defdir"))]["NAME"] = n + _[p]["DIR"] = f + return p +} + +#_________________________________________________________________________________________ +function _defdll(pp, n, rn, p) +{ + ############################################################## + _[p = _wLCHLD(pp, _n("TYPE", "defdll"))]["NAME"] = n + _[p]["REGPATH"] = _[pp]["REGPATH"] rn + _[p]["ERRHOST"] = pp + return p +} + +#___________________________________________________________ +function _defescarr(D, r, S, i, c, t) +{ + if (isarray(S)) { + for (i = 0; i < 256; i++) { + if ((c = _CHR[i]) ~ r) { + D[c] = "\\" S[c] + t = t c + } else { + if (D[c] == "") { + D[c] = c + } + } } - i = split(_cmd("dir \"" rd "\" 2>NUL"), B, /\x0D?\x0A/) - 3 - pf = (match(B[4], /Directory of ([^\x00-\x1F]+)/, C) ? C[1] ((C[1] ~ /\\$/ ? "" : "\\")) : "") - for (r = 0; i > 5; i--) { - if (match(B[i], /^([^ \t]*)[ \t]+([^ \t]*)[ \t]+((<DIR>)|([0-9\,]+))[ \t]+([^\x00-\x1F]+)$/, C)) { - if (C[6] !~ /^\.\.?$/) { - if (C[4]) { - ds = "D " - } else { - ds = C[5] " " - gsub(/\,/, "", ds) - } - if ((f = _filepath(pf C[6] ((C[4] ? "\\" : "")))) != "") { - A[f] = ds C[1] " " C[2] - r++ - } + } else { + for (i = 0; i < 256; i++) { + if ((c = _CHR[i]) ~ r) { + D[c] = S c + if (S != "") { + t = t c + } + } else { + if (D[c] == "") { + D[c] = c } } } - return r } - - function _dirtree(A, f, B) - { - #_________________________________________________________________ - ######################################### - gsub(/(^[ \t]*)|([ \t]*$)/, "", f) - delete A - A[""] - delete A[""] - _dirtree_i0(B, 8, split(_cmd("dir \"" f "\" /-C /S 2>NUL"), B, /\x0D?\x0A/), A, f = _filerd(f)) - return f + return t +} + +#_________________________________________________________________________________________ +function _defile(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defile"))]["NAME"] = n + _[p]["FILE"] = f + if (! (v == 0 && v == "")) { + _[p]["RQVERSION"] = v + } + return p +} + +#_______________________________________________________________________ +function _defn(f, c, v) +{ + ################################################### + FUNCTAB[c f] = v +} + +#_________________________________________________________________________________________ +function _defreg(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defreg"))]["NAME"] = n + _[p]["REGPATH"] = f + if (! (v == 0 && v == "")) { + _[p]["VALUE"] = v + } +} + +#_______________________________________________________________________________________________ +function _defsolution(pp, n, rn, p) +{ + ############################################################### + _[p = _wLCHLD(pp, _n("TYPE", "solution"))]["NAME"] = n + _[p]["REGPATH"] = rn + _[p]["ERRHOST"] = pp + return p +} + +#_________________________________________________________________________________________ +function _defsrv(pp, n, f, v, p) +{ + ############################################################# + _[p = _wLCHLD(pp, _n("TYPE", "defsrv"))]["NAME"] = n + _[p]["SERVNAME"] = f + return p +} + +#_______________________________________________________________________ +function _del(f, c, a, A) +{ + ################################################# + if (match(f, /\\[ \t]*$/)) { + if ((c = toupper(_filerd(f))) && length(f) == FLENGTH) { + _cmd("rd " c " /S /Q 2>NUL") + _deletepfx(_WFILEROOTDIR, c) + _deletepfx(_FILEIO_RDTMP, c) + _deletepfx(_FILEIO_RDNETMP, c) + } else { + _conl("HUJ TEBE!") + return "" + } + } else { + a = _dir(A, f) + _cmd("del " f " /Q 2>NUL") + for (c in A) { + if (c ~ /\\$/) { + _cmd("rd " c " /S /Q 2>NUL") + _deletepfx(_WFILEROOTDIR, c) + _deletepfx(_FILEIO_RDTMP, c) + } + _deletepfx(_FILEIO_RDNETMP, c) + } + } + return a +} + +#_______________________________________________________________________ +function _delay(t, a) +{ + ################################################### + for (a = 1; a <= t; a++) { + _delayms() + } +} + +#_________________________________________________________________ +function _delayms(a) +{ + ############################################# + for (a = 1; a <= _delay_perfmsdelay; a++) { + } +} + +#_______________________________________________________________________ +function _deletepfx(A, f, B, le, i) +{ + ######################################## + le = length(f) + for (i in A) { + if (substr(toupper(i), 1, le) == f) { + B[i] = A[i] + delete A[i] + } + } +} + +#_________________________________________________________________ +function _delf(A, f) +{ + ############################################### + A["B"][A["F"][A["B"][f]] = A["F"][f]] = A["B"][f] + delete A["F"][f] + delete A["B"][f] +} + +#_______________________________________________________________________ +function _deluid(p) +{ + ################################################# 1 # + if (p in _CLASSPTR) { + _deluida0 = _CLASSPTR[p] + if (_deluida0 in _UIDOBL) { + _UIDOBLV[_UIDOBL[_deluida0]][p] + } + } + delete _CLASSPTR[p] + return _deluida0 +} + +#_______________________________________________________________________ +function _dir(A, rd, i, r, f, ds, pf, B, C) +{ + #################################### + delete A + gsub(/(^[ \t]*)|([ \t]*$)/, "", rd) + if (rd == "") { + return "" } - - function _dirtree_i0(B, i, c, A, f, lf, a, C) - { - #___________________________________________________________ - delete A[f] - A[f][0] - delete A[f][0] - lf = length(f) - for (; i <= c; ) { - if (match(B[i], /^[ \t]*Directory of (.+)/, C)) { - if (substr(a = _filerd(C[1] "\\"), 1, lf) == f) { - i = _dirtree_i0(B, i + 4, c, A[f], a) + i = split(_cmd("dir \"" rd "\" 2>NUL"), B, /\x0D?\x0A/) - 3 + pf = (match(B[4], /Directory of ([^\x00-\x1F]+)/, C) ? C[1] ((C[1] ~ /\\$/ ? "" : "\\")) : "") + for (r = 0; i > 5; i--) { + if (match(B[i], /^([^ \t]*)[ \t]+([^ \t]*)[ \t]+((<DIR>)|([0-9\,]+))[ \t]+([^\x00-\x1F]+)$/, C)) { + if (C[6] !~ /^\.\.?$/) { + if (C[4]) { + ds = "D " } else { - return i + ds = C[5] " " + gsub(/\,/, "", ds) } - } else { - if (match(B[i++], /^([^ \t\-]+)\-([^ \t\-]+)\-([^ \t]+)[ \t]+([^ \t]+)[ \t]+([0-9]+)[ \t]+(.+)$/, C)) { - A[f][f C[6]] = C[5] " " C[1] "/" _CHR["MONTH"][C[2]] "/" C[3] " " C[4] + if ((f = _filepath(pf C[6] ((C[4] ? "\\" : "")))) != "") { + A[f] = ds C[1] " " C[2] + r++ } } } - return i } - - function _dll_check(pp) - { - #_______________________________________________________________________ - _dllchktv = "" - _missfl = 1 - #also check that all dll have same version; also check that all dlls have success and then report that DS plug-in version n - installed - _tframe("_dll_check_i0", pp, _REG, pp) - if (1 || "AGENT" in _[pp]) { - if (_dllchktv != _[pp][".Product Version"]) { - _dllerr(_[pp]["AGENT"], "agent version (" _[pp][".Product Version"] ") do not match all lib versions: " _dllchktv "'") + return r +} + +#_________________________________________________________________ +function _dirtree(A, f, B) +{ + ######################################### + gsub(/(^[ \t]*)|([ \t]*$)/, "", f) + delete A + A[""] + delete A[""] + _dirtree_i0(B, 8, split(_cmd("dir \"" f "\" /-C /S 2>NUL"), B, /\x0D?\x0A/), A, f = _filerd(f)) + return f +} + +#___________________________________________________________ +function _dirtree_i0(B, i, c, A, f, lf, a, C) +{ + delete A[f] + A[f][0] + delete A[f][0] + lf = length(f) + for (; i <= c; ) { + if (match(B[i], /^[ \t]*Directory of (.+)/, C)) { + if (substr(a = _filerd(C[1] "\\"), 1, lf) == f) { + i = _dirtree_i0(B, i + 4, c, A[f], a) + } else { + return i } } else { - if (! _missfl) { - _creport(pp, "agent not detected in registry") - } else { - _dllerr(pp, "agent not detected in registry but some registry entries exist:") - _tframe("_dll_check_i1", pp, pp) + if (match(B[i++], /^([^ \t\-]+)\-([^ \t\-]+)\-([^ \t]+)[ \t]+([^ \t]+)[ \t]+([0-9]+)[ \t]+(.+)$/, C)) { + A[f][f C[6]] = C[5] " " C[1] "/" _CHR["MONTH"][C[2]] "/" C[3] " " C[4] } } } + return i +} - function _dll_check_i0(p, R, pp, p2, i, i2, r, f, v, rs, d, tv, tf) - { - if (_[p]["TYPE"] == "defdll") { - #_______________________________________________ - r = toupper(_[p]["REGPATH"]) - rs = 0 - tf = 0 - tv = "" - #{ rs=_missfl=1; _[p]["." gensub(/^([^\\]+\\)+(.*)\..../,"\\2","G",i)]=R[i] } } - for (i in R) { - if (toupper(substr(i, 1, length(r))) == r) { - if ((_chka0 = substr(i, 1 + length(r), 1)) == "" || _chka0 == "\\") { +#_______________________________________________________________________ +function _dll_check(pp) +{ + _dllchktv = "" + _missfl = 1 + _tframe("_dll_check_i0", pp, _REG, pp) + #also check that all dll have same version; also check that all dlls have success and then report that DS plug-in version n - installed + if (1 || "AGENT" in _[pp]) { + if (_dllchktv != _[pp][".Product Version"]) { + _dllerr(_[pp]["AGENT"], "agent version (" _[pp][".Product Version"] ") do not match all lib versions: " _dllchktv "'") + } + } else { + if (! _missfl) { + _creport(pp, "agent not detected in registry") + } else { + _dllerr(pp, "agent not detected in registry but some registry entries exist:") + _tframe("_dll_check_i1", pp, pp) + } + } +} + +#_______________________________________________ +function _dll_check_i0(p, R, pp, p2, i, i2, r, f, v, rs, d, tv, tf) +{ + if (_[p]["TYPE"] == "defdll") { + r = toupper(_[p]["REGPATH"]) + rs = 0 + tf = 0 + tv = "" + for (i in R) { + if (toupper(substr(i, 1, length(r))) == r) { + if ((_chka0 = substr(i, 1 + length(r), 1)) == "" || _chka0 == "\\") { + rs = 1 + _missfl = 1 + _[p]["." substr(gensub(/\....$/, "", 1, i), i2 = 2 + length(r), length(i) - i2 + 1)] = R[i] + if (chka0 != "") { rs = 1 - _missfl = 1 - _[p]["." substr(gensub(/\....$/, "", 1, i), i2 = 2 + length(r), length(i) - i2 + 1)] = R[i] - if (chka0 != "") { - rs = 1 - } } } } - if (rs) { - if ((i = ".Install Path") in _[p] && (i = ".Product Version") in _[p]) { - _[p]["STATUS"] = "PRESENT" - f = _[p][".Install Path"] - v = _[p][".Product Version"] - if (! (".Module" in _[p])) { - _[pp][".Product Version"] = v - _VAR["HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR"] = f - _[pp]["AGENT"] = p - _creport("OK: DLL DETECTED(" v "): " substr(_[p]["NAME"], 1, 112)) + } + #{ rs=_missfl=1; _[p]["." gensub(/^([^\\]+\\)+(.*)\..../,"\\2","G",i)]=R[i] } } + if (rs) { + if ((i = ".Install Path") in _[p] && (i = ".Product Version") in _[p]) { + _[p]["STATUS"] = "PRESENT" + f = _[p][".Install Path"] + v = _[p][".Product Version"] + if (! (".Module" in _[p])) { + _[pp][".Product Version"] = v + _VAR["HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR"] = f + _[pp]["AGENT"] = p + _creport("OK: DLL DETECTED(" v "): " substr(_[p]["NAME"], 1, 112)) + } else { + if (_dllchktv == "") { + _dllchktv = v } else { - if (_dllchktv == "") { - _dllchktv = v - } else { - if (v != _dllchktv) { - return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'") - } - } - ERRNO = "" - if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { - delete _[p]["DATA"] - return _dllerr(p, "read lib: " ERRNO, f) + if (v != _dllchktv) { + return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'") } - if (v != (_[p]["VERSION"] = _getfilever(f))) { - return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) - } - _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100)) } - } else { - tf = 1 - _dllerr(p, "registry corrupt: `" i "' not present") + ERRNO = "" + if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { + delete _[p]["DATA"] + return _dllerr(p, "read lib: " ERRNO, f) + } + if (v != (_[p]["VERSION"] = _getfilever(f))) { + return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + } + _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100)) } } else { - _[p]["STATUS"] = "MISSED" + tf = 1 + _dllerr(p, "registry corrupt: `" i "' not present") } + } else { + _[p]["STATUS"] = "MISSED" } } +} - function _dll_check_i1(p, pp, p1, p2, p3, i) - { - if (_[p]["TYPE"] == "defdll") { - for (i in _[p]) { - #_______________________________________________ - if (i ~ /^\./) { - _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2)) - } +#_______________________________________________ +function _dll_check_i1(p, pp, p1, p2, p3, i) +{ + if (_[p]["TYPE"] == "defdll") { + for (i in _[p]) { + if (i ~ /^\./) { + _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2)) } } } +} - function _dllerr(p, t, f) - { - #___________________________________________________________________________________ - if (t !~ /\x00/) { - t = "ERROR: \000" t - } - _errfl = 1 - _[p]["ERROR"] = _[p]["ERROR"] _ln(t ((f == "" ? "" : ": " f))) +#___________________________________________________________________________________ +function _dllerr(p, t, f) +{ + if (t !~ /\x00/) { + t = "ERROR: \000" t } + _errfl = 1 + _[p]["ERROR"] = _[p]["ERROR"] _ln(t ((f == "" ? "" : ": " f))) +} - function _drawuid(p, cn, ch, o) - { - _conl("uid: " p) - _conl("\toblptr: " ((p in _UIDOBL ? _UIDOBL[p] "'" : "-"))) - if (p in _UIDOBL) { - if (! _isptr(o = _UIDOBL[p])) { - _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer") - } - if (! isarray(_UIDOBLV[o])) { - _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr") - } - } - _conl("\tprefix: " ((p in _UIDPFX ? _UIDPFX[p] "'" : "-"))) - _conl("\tsuffix: " ((p in _UIDSFX ? _UIDSFX[p] "'" : "-"))) - _conl("\tcounters: " (cn = (p in _UIDCNT ? _UIDCNT[p] "'" : "-"))) - if (cn != "-") { - _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'") - _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'") +function _drawuid(p, cn, ch, o) +{ + _conl("uid: " p) + _conl("\toblptr: " ((p in _UIDOBL ? _UIDOBL[p] "'" : "-"))) + if (p in _UIDOBL) { + if (! _isptr(o = _UIDOBL[p])) { + _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer") } - _conl("\tcharset: " (ch = (p in _UIDCHR ? _UIDCHR[p] "'" : "-"))) - if (ch != "-") { - _conl("chrH: ") - _conl(_dumparr(_UIDCHRH[_UIDCHR[p]])) - _conl() - _conl("chrL: ") - _conl(_dumparr(_UIDCHRL[_UIDCHR[p]])) - _conl() + if (! isarray(_UIDOBLV[o])) { + _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr") } } - - function _dumparr(A, t, lv, a) - { - #_______________________________________________________________________ - ############################################ - b = PROCINFO["sorted_in"] - PROCINFO["sorted_in"] = "_lengthsort" - if (isarray(A)) { - delete _DUMPARR - _dumparrc = _dumparrd = "" - _dumparr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) - PROCINFO["sorted_in"] = a - return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") - } + _conl("\tprefix: " ((p in _UIDPFX ? _UIDPFX[p] "'" : "-"))) + _conl("\tsuffix: " ((p in _UIDSFX ? _UIDSFX[p] "'" : "-"))) + _conl("\tcounters: " (cn = (p in _UIDCNT ? _UIDCNT[p] "'" : "-"))) + if (cn != "-") { + _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'") + _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'") } - - function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f) - { - #___________________________________________________________ - t2 = _getchrln(" ", length(t)) - if (ln == lv) { - if (ls > 0) { - for (i in A) { - ++a - } - } else { - for (i in A) { - (isarray(A[i]) ? ++a : "") - } - } - if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" + _conl("\tcharset: " (ch = (p in _UIDCHR ? _UIDCHR[p] "'" : "-"))) + if (ch != "-") { + _conl("chrH: ") + _conl(_dumparr(_UIDCHRH[_UIDCHR[p]])) + _conl() + _conl("chrL: ") + _conl(_dumparr(_UIDCHRL[_UIDCHR[p]])) + _conl() + } +} + +#_______________________________________________________________________ +function _dumparr(A, t, lv, a) +{ + ############################################ + b = PROCINFO["sorted_in"] + PROCINFO["sorted_in"] = "_lengthsort" + if (isarray(A)) { + delete _DUMPARR + _dumparrc = _dumparrd = "" + _dumparr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) + PROCINFO["sorted_in"] = a + return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") + } +} + +#___________________________________________________________ +function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f) +{ + t2 = _getchrln(" ", length(t)) + if (ln == lv) { + if (ls > 0) { + for (i in A) { + ++a } - return - } - if (ls >= 0) { + } else { for (i in A) { - if (! isarray(A[i])) { - if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" - } - } + (isarray(A[i]) ? ++a : "") } } - for (i in A) { - if (isarray(A[i])) { - _dumparr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") - } + if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" } - if (! f) { - if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { - _DUMPARR[++_dumparrc] = _dumparrd - _dumparrd = "" + return + } + if (ls >= 0) { + for (i in A) { + if (! isarray(A[i])) { + if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" + } } } } - - function _dumpobj(p, f, t, s) - { - #___________________________________________________________________________________ - #################################################################################### - #___________________________________________________________________________________ - # OTHER tFUNCTIONs ################################################################# - #_____________________________________________________________________________ - ################################################### - s = _dumpobj_i0(p, f, t = t "." p "{") - if (p = _rFCHLD(p)) { - return (s = s _dumpobjm(p, f, (s ? _getchrln(" ", length(t) - 1) : t " "))) + for (i in A) { + if (isarray(A[i])) { + _dumparr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") } - return s } - - function _dumpobj_i0(p, f, t) - { - #___________________________________________________________ - if (f == "") { - return _dumpobj_i2(p, t) - } - if (f == 0) { - return _dumpobj_i1(p, t " ") + if (! f) { + if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { + _DUMPARR[++_dumparrc] = _dumparrd + _dumparrd = "" } - return (_dumpobj_i1(p, t " ") _dumpobj_i2(p, _getchrln(" ", length(t)))) } +} - function _dumpobj_i1(p, t) - { - #___________________________________________________________ - return _ln(t substr(((p in _tPREV ? "\253" _tPREV[p] : "")) " ", 1, 7) " " substr(((p in _tPARENT ? "\210" _tPARENT[p] : "")) " ", 1, 7) " " substr(((p in _tFCHLD ? _tFCHLD[p] : "")) "\205" ((p in _tQCHLD ? " (" _tQCHLD[p] ") " : "\205")) "\205" ((p in _tLCHLD ? _tLCHLD[p] : "")) " ", 1, 22) substr(((p in _tNEXT ? "\273" _tNEXT[p] : "")) " ", 1, 8)) +#___________________________________________________________________________________ +#################################################################################### + + +#___________________________________________________________________________________ +# OTHER tFUNCTIONs ################################################################# + +#_____________________________________________________________________________ +function _dumpobj(p, f, t, s) +{ + ################################################### + s = _dumpobj_i0(p, f, t = t "." p "{") + if (p = _rFCHLD(p)) { + return (s = s _dumpobjm(p, f, (s ? _getchrln(" ", length(t) - 1) : t " "))) } + return s +} - function _dumpobj_i2(p, t) - { - #___________________________________________________________ - return (_dumpobj_i3(_[p], t " ") _dumpobj_i3(_ptr[p], _getchrln(" ", length(t)) "`", "`")) +#___________________________________________________________ +function _dumpobj_i0(p, f, t) +{ + if (f == "") { + return _dumpobj_i2(p, t) } + if (f == 0) { + return _dumpobj_i1(p, t " ") + } + return (_dumpobj_i1(p, t " ") _dumpobj_i2(p, _getchrln(" ", length(t)))) +} + +#___________________________________________________________ +function _dumpobj_i1(p, t) +{ + return _ln(t substr(((p in _tPREV ? "\253" _tPREV[p] : "")) " ", 1, 7) " " substr(((p in _tPARENT ? "\210" _tPARENT[p] : "")) " ", 1, 7) " " substr(((p in _tFCHLD ? _tFCHLD[p] : "")) "\205" ((p in _tQCHLD ? " (" _tQCHLD[p] ") " : "\205")) "\205" ((p in _tLCHLD ? _tLCHLD[p] : "")) " ", 1, 22) substr(((p in _tNEXT ? "\273" _tNEXT[p] : "")) " ", 1, 8)) +} - function _dumpobj_i3(A, t, p, e, s, i, t2) - { - if (isarray(A)) { +#___________________________________________________________ +function _dumpobj_i2(p, t) +{ + return (_dumpobj_i3(_[p], t " ") _dumpobj_i3(_ptr[p], _getchrln(" ", length(t)) "`", "`")) +} + +#___________________________________________________________ +function _dumpobj_i3(A, t, p, e, s, i, t2) +{ + if (isarray(A)) { + for (i in A) { + t2 = _getchrln(" ", length(t)) for (i in A) { - #___________________________________________________________ - t2 = _getchrln(" ", length(t)) - for (i in A) { - if (isarray(A[i])) { - s = s _dumpobj_i3(A[i], t "[" _dumpobj_i4(i) "]", p, _ln()) - } else { - s = s _ln(t "[" _dumpobj_i4(i) "]=" p _dumpobj_i4(A[i]) "'") - } - t = t2 + if (isarray(A[i])) { + s = s _dumpobj_i3(A[i], t "[" _dumpobj_i4(i) "]", p, _ln()) + } else { + s = s _ln(t "[" _dumpobj_i4(i) "]=" p _dumpobj_i4(A[i]) "'") } - return s + t = t2 } - return ((e == "" ? "" : t e)) - } - if (A == 0 && A == "") { - return - } - return _ln(t "=" _dumpobj_i4(p A) "'") - } - - function _dumpobj_i4(t) - { - #___________________________________________________________ - if (length(t) > 64) { - return (substr(t, 1, 28) " ... " substr(t, length(t) - 28)) + return s } - return t + return ((e == "" ? "" : t e)) } - - function _dumpobj_nc(p, f, t) - { - #_________________________________________________________________ - ####################################### - return _dumpobj_i0(p, f, t "." p "{ ") + if (A == 0 && A == "") { + return } - - function _dumpobjm(p, f, t, s, t2) - { - #_________________________________________________________________ - ################################### - t2 = _getchrln(" ", length(t)) - do { - s = s _dumpobj(p, f, t) - t = t2 - } while (p = _rNEXT(p)) - return s + return _ln(t "=" _dumpobj_i4(p A) "'") +} + +#___________________________________________________________ +function _dumpobj_i4(t) +{ + if (length(t) > 64) { + return (substr(t, 1, 28) " ... " substr(t, length(t) - 28)) + } + return t +} + +#_________________________________________________________________ +function _dumpobj_nc(p, f, t) +{ + ####################################### + return _dumpobj_i0(p, f, t "." p "{ ") +} + +#_________________________________________________________________ +function _dumpobjm(p, f, t, s, t2) +{ + ################################### + t2 = _getchrln(" ", length(t)) + do { + s = s _dumpobj(p, f, t) + t = t2 + } while (p = _rNEXT(p)) + return s +} + +#_________________________________________________________________ +function _dumpobjm_nc(p, f, t, s, t2) +{ + ################################ + t2 = _getchrln(" ", length(t)) + do { + s = s _dumpobj_nc(p, f, t) + t = t2 + } while (p = _rNEXT(p)) + return s +} + +function _dumpuidgen(p, pd, pc, ps) +{ + _conline("#" ++cntdm ": " p "'") + _conl() + if (p in _tuidel) { + _conl("DEL: " _var(pd = _tuidel[p])) + _conl(_dumparr(_tUIDEL[pd]) _ln()) + } + _conl("PFX: " _tUIDPFX[p] "'") + _conl("SFX: " _tUIDSFX[p] "'") + _conl("COUNT: " ((p in _tuidcnt ? (pc = _tuidcnt[p]) "'" : _th0("-", pc = -2)))) + _con("CHARS: ") + if (p in _tuidchr) { + _conl((ps = _tuidchr[p]) "'") + _conl("HCHR: " ((pc == -2 ? "-" : _tUIDCNTH[pc] "'"))) + _conl(_dumparr(_tUIDCHRH[ps]) _ln()) + _conl("LCHR: " ((pc == -2 ? "-" : _tUIDCNTL[pc] "'"))) + _conl(_dumparr(_tUIDCHRL[ps]) _ln()) + } else { + _conl("-") + } +} + +#_____________________________________________________________________________ +function _dumpval(v, n) +{ + _dumpstr = _dumpstr (v = _ln(((n == 0 && n == "" ? "RET" : n)) ": " ((v == 0 && v == "" ? "-" : v "'")))) + return v +} + +######################################################## + +function _eXTFN(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + return t + #___________________________________________________________ + + case "_lib_APPLY": + return + #___________________________________________________________ + + case "_lib_HELP": + return + #___________________________________________________________ + + case "_lib_NAMEVER": + return _ln("_extfn 1.0") + #___________________________________________________________ + + case "_lib_BEGIN": + return + #___________________________________________________________ + + case "_lib_END": + return } - - function _dumpobjm_nc(p, f, t, s, t2) - { - #_________________________________________________________________ - ################################ - t2 = _getchrln(" ", length(t)) - do { - s = s _dumpobj_nc(p, f, t) - t = t2 - } while (p = _rNEXT(p)) - return s +} + +#_________________________________________________________________ +function _endpass(t) +{ + _endpass_v0 = t +} + +#_______________________________________________________________________ +function _err(t, a, b) +{ + ################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > _SYS_STDERR + fflush(_SYS_STDERR) + BINMODE = a + ORS = b + return t +} + +#_________________________________________________________________ +function _errnl(t) +{ + ################################################ + return _err(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) +} + +#_______________________________________________________________________ +function _error(t, d, A) +{ + ################################################# + if (_ERRLOG_EF) { + A["TYPE"] = "ERROR" + A["TEXT"] = t + _log(A, d) + } +} + +#_______________________________________________________________________ +function _exit(c) +{ + ####################################################### + exit c +} + +#_____________________________________________________________________________ +function _export_data(t, i, A) +{ + ################################################# + A["DATA"] = t + A["ID"] = i + _expout("_DATA: " _Zexparr(A) "\n") +} + +#___________________________________________________________________________________ +#################################################################################### + +#_____________________________________________________________________________ +function _expout(t, d, a, b) +{ + #################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > ((d ? d : d = _errlog_file)) + fflush(d) + BINMODE = a + ORS = b +} + +#_________________________________________________________________________________________ +########################################################################################## + + + + + + + + +function _extfn_init() +{ + ############################################################## + + _formatstrs_init() + _formatstrd_init() + _formatrexp_init() + _unformatstr_init() + _mac_init() +} + +function _faccl_i0(A, t, p, P, f, r) +{ + f = r = "" + if (isarray(A)) { + while (f = A[f]) { + r = (@f(t, p, P)) r + } + } + return r +} + +function _faccr_i0(A, t, p, P, f, r) +{ + f = r = "" + if (isarray(A)) { + while (f = A[f]) { + r = r @f(t, p, P) + } + } + return r +} + +#_______________________________________________________________________ +function _fatal(t, d, A) +{ + ################################################# + if (_ERRLOG_FF) { + A["TYPE"] = "FATAL" + A["TEXT"] = t + _log(A, d) + } + if (! d) { + exit + } +} + +function _fbaccl(A, t, p, P) +{ + return _faccl_i0(A["B"], t, p, P) +} + +function _fbaccr(A, t, p, P) +{ + return _faccr_i0(A["B"], t, p, P) +} + +function _ffaccl(A, t, p, P) +{ + return _faccl_i0(A["F"], t, p, P) +} + +function _ffaccr(A, t, p, P) +{ + return _faccr_i0(A["F"], t, p, P) +} + +################## +#_______________________________________________________________________ +function _fframe(A, t, p) +{ + ################################################# + return _fframe_i0(A, t, p, A[""]) +} + +#___________________________________________________________ +function _fframe_i0(A, t, p, f) +{ + return ((f ? (@f(t, p)) _fframe_i0(A, t, p, A[f]) : "")) +} + +#_________________________________________________________________ +function _file(f) +{ + ################################################# + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _dumpuidgen(p, pd, pc, ps) - { - _conline("#" ++cntdm ": " p "'") - _conl() - if (p in _tuidel) { - _conl("DEL: " _var(pd = _tuidel[p])) - _conl(_dumparr(_tUIDEL[pd]) _ln()) - } - _conl("PFX: " _tUIDPFX[p] "'") - _conl("SFX: " _tUIDSFX[p] "'") - _conl("COUNT: " ((p in _tuidcnt ? (pc = _tuidcnt[p]) "'" : _th0("-", pc = -2)))) - _con("CHARS: ") - if (p in _tuidchr) { - _conl((ps = _tuidchr[p]) "'") - _conl("HCHR: " ((pc == -2 ? "-" : _tUIDCNTH[pc] "'"))) - _conl(_dumparr(_tUIDCHRH[ps]) _ln()) - _conl("LCHR: " ((pc == -2 ? "-" : _tUIDCNTL[pc] "'"))) - _conl(_dumparr(_tUIDCHRL[ps]) _ln()) + return ((f in _FILEXT ? _FILEXT[f] : "")) +} + +#_______________________________________________________________________ +function _file_check(p) +{ + if (1 || "AGENT" in _[p]) { + _tframe("_file_check_i0", p, p) + } +} + +#_______________________________________________ +function _file_check_i0(p, pp, p1, p2, f, v) +{ + if (_[p]["TYPE"] == "defile") { + f = _[p]["FILE"] + f = ((match(f, /^.:/) ? "" : _[_[pp]["AGENT"]][".Install Path"] "\\")) _[p]["FILE"] + if ("RQVERSION" in _[p]) { + v = _[p]["RQVERSION"] } else { - _conl("-") + v = _[pp][".Product Version"] + } + ERRNO = "" + if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { + delete _[p]["DATA"] + return _dllerr(p, "read file: " ERRNO, f) + } + if (v != "" && v != (_[p]["VERSION"] = _getfilever(f))) { + return _dllerr(p, " file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + } + _creport(p, substr("OK: FILE DETECTED" ((v == "" ? "" : "(" v ")")) ": " f, 1, 122)) + } else { + if (_[p]["TYPE"] == "defdir") { + if (_filexist(f = _[p]["DIR"])) { + _creport(p, substr("OK: DIR DETECTED: " f, 1, 112)) + } else { + _dllerr(p, "directory " f " is not detected") + } } } +} - function _dumpval(v, n) - { - #_____________________________________________________________________________ - _dumpstr = _dumpstr (v = _ln(((n == 0 && n == "" ? "RET" : n)) ": " ((v == 0 && v == "" ? "-" : v "'")))) - return v +#_________________________________________________________________ +function _filed(f, dd, d) +{ + ########################################## + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _eXTFN(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ######################################################## - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_extfn 1.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - return - } + if (f in _FILEDIRFL) { + return _FILEDIR[f] } - - function _endpass(t) - { - #_________________________________________________________________ - _endpass_v0 = t + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] + } + return (_FILEDIR[f] = d _FILEDIR[f]) } - - function _err(t, a, b) - { - #_______________________________________________________________________ - ################################################### - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > _SYS_STDERR - fflush(_SYS_STDERR) - BINMODE = a - ORS = b - return t + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEDIR) { + return _FILEDIR[dd, f] } - - function _errnl(t) - { - #_________________________________________________________________ - ################################################ - return _err(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) + if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { + return (_FILEDIR[dd, f] = d) } + return d +} - function _error(t, d, A) - { - if (_ERRLOG_EF) { - #_______________________________________________________________________ - ################################################# - A["TYPE"] = "ERROR" - A["TEXT"] = t - _log(A, d) - } +#_________________________________________________________________ +function _filen(f) +{ + ################################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return ((f in _FILENAM ? _FILENAM[f] : "")) +} - function _exit(c) - { - #_______________________________________________________________________ - ####################################################### - exit c +#_________________________________________________________________ +function _filene(f) +{ + ############################################### + if ((f = _filerdnehnd(f)) == "") { + return "" } + return (((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) +} - function _export_data(t, i, A) - { - #_____________________________________________________________________________ - ################################################# - A["DATA"] = t - A["ID"] = i - _expout("_DATA: " _Zexparr(A) "\n") +#_________________________________________________________________ +function _filenotexist(f, a) +{ + ###################################### + if (f == "") { + return "" } - - function _expout(t, d, a, b) - { - #___________________________________________________________________________________ - #################################################################################### - #_____________________________________________________________________________ - #################################################### - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > ((d ? d : d = _errlog_file)) - fflush(d) - BINMODE = a - ORS = b + if ((a = _filepath(f)) == "") { + ERRNO = "Filepath error `" f "'" + return "" } - - function _extfn_init() - { - #_________________________________________________________________________________________ - ########################################################################################## - ############################################################## - _formatstrs_init() - _formatstrd_init() - _formatrexp_init() - _unformatstr_init() - _mac_init() - } - - function _faccl_i0(A, t, p, P, f, r) - { - f = r = "" - if (isarray(A)) { - while (f = A[f]) { - r = (@f(t, p, P)) r - } - } - return r + _cmd("if exist \"" a "\" exit 1 2>NUL") + if (_exitcode == 1) { + return (ERRNO = _NOP) } + return a +} - function _faccr_i0(A, t, p, P, f, r) - { - f = r = "" - if (isarray(A)) { - while (f = A[f]) { - r = r @f(t, p, P) - } - } - return r +#_______________________________________________________________________ +function _filepath(f, dd) +{ + ################################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return (filegetrootdir(f, dd) ((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) +} - function _fatal(t, d, A) - { - if (_ERRLOG_FF) { - #_______________________________________________________________________ - ################################################# - A["TYPE"] = "FATAL" - A["TEXT"] = t - _log(A, d) - } - if (! d) { - exit - } +#_________________________________________________________________ +function _filer(f, dd) +{ + ############################################# + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _fbaccl(A, t, p, P) - { - return _faccl_i0(A["B"], t, p, P) + if (f in _FILEROOT) { + return _FILEROOT[f] } - - function _fbaccr(A, t, p, P) - { - return _faccr_i0(A["B"], t, p, P) + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { + return _FILEROOT[dd, f] } + return (_FILEROOT[dd, f] = fileri(dd)) +} - function _ffaccl(A, t, p, P) - { - return _faccl_i0(A["F"], t, p, P) +#_________________________________________________________________ +function _filerd(f, dd) +{ + ############################################ + if ((f = _filerdnehnd(f)) == "") { + return "" } + return filegetrootdir(f, dd) +} - function _ffaccr(A, t, p, P) - { - return _faccr_i0(A["F"], t, p, P) +#_________________________________________________________________ +function _filerdn(f, dd) +{ + ########################################### + if ((f = _filerdnehnd(f)) == "") { + return "" } + return ((f in _FILENAM ? filegetrootdir(f, dd) _FILENAM[f] : "")) +} - function _fframe(A, t, p) - { - ################## - #_______________________________________________________________________ - ################################################# - return _fframe_i0(A, t, p, A[""]) +#_________________________________________________________________ +function _filerdne(f, dd) +{ + ########################################## + if ((f = _filerdnehnd(f)) == "") { + return "" } - - function _fframe_i0(A, t, p, f) - { - #___________________________________________________________ - return ((f ? (@f(t, p)) _fframe_i0(A, t, p, A[f]) : "")) + if (f in _FILENAM) { + return (filegetrootdir(f, dd) _FILENAM[f] ((f in _FILEXT ? _FILEXT[f] : ""))) } - - function _file(f) - { - #_________________________________________________________________ - ################################################# - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILEXT ? _FILEXT[f] : "")) + if (f in _FILEXT) { + return (filegetrootdir(f, dd) _FILEXT[f]) } + return "" +} - function _file_check(p) - { - if (1 || "AGENT" in _[p]) { - #_______________________________________________________________________ - _tframe("_file_check_i0", p, p) +#___________________________________________________________ +function _filerdnehnd(st, c, r, d, n, A) +{ + if (st) { + if ((c = toupper(st)) in _FILECACHE) { + FLENGTH = length(st) + return _FILECACHE[c] } - } - - function _file_check_i0(p, pp, p1, p2, f, v) - { - if (_[p]["TYPE"] == "defile") { - #_______________________________________________ - f = _[p]["FILE"] - f = ((match(f, /^.:/) ? "" : _[_[pp]["AGENT"]][".Install Path"] "\\")) _[p]["FILE"] - if ("RQVERSION" in _[p]) { - v = _[p]["RQVERSION"] + if (match(st, /^[ \t]*\\[ \t]*\\/)) { + if (match(substr(st, (FLENGTH = RLENGTH) + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { + FLENGTH = FLENGTH + RLENGTH + d = ((A[3] ? "\\" A[3] "$" : "")) A[4] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) + } + _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + _FILEDIRFL[c] + _FILEROOT[c] = r } else { - v = _[pp][".Product Version"] + FLENGTH = 0 + _filepath_err = "UNC" + return "" } - ERRNO = "" - if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) { - delete _[p]["DATA"] - return _dllerr(p, "read file: " ERRNO, f) + } else { + match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) + if (! (FLENGTH = RLENGTH)) { + return "" } - if (v != "" && v != (_[p]["VERSION"] = _getfilever(f))) { - return _dllerr(p, " file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f) + d = A[8] A[10] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) } - _creport(p, substr("OK: FILE DETECTED" ((v == "" ? "" : "(" v ")")) ": " f, 1, 122)) - } else { - if (_[p]["TYPE"] == "defdir") { - if (_filexist(f = _[p]["DIR"])) { - _creport(p, substr("OK: DIR DETECTED: " f, 1, 112)) - } else { - _dllerr(p, "directory " f " is not detected") - } + _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + if (A[8]) { + _FILEDIRFL[c] } - } - } - - function _filed(f, dd, d) - { - #_________________________________________________________________ - ########################################## - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILEDIRFL) { - return _FILEDIR[f] - } - if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] + if (r) { + _FILEROOT[c] = r } - return (_FILEDIR[f] = d _FILEDIR[f]) - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEDIR) { - return _FILEDIR[dd, f] } - if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return (_FILEDIR[dd, f] = d) + if (n) { + if (match(n, /\.[^\.]*$/)) { + _FILEXT[c] = substr(n, RSTART) + _FILENAM[c] = substr(n, 1, RSTART - 1) + } else { + _FILENAM[c] = n + } } - return d + return c } + return "" +} - function _filen(f) - { - #_________________________________________________________________ - ################################################ - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILENAM ? _FILENAM[f] : "")) +#_______________________________________________________________________ +function _filexist(f, a) +{ + ################################################ + if (f == "") { + return "" } - - function _filene(f) - { - #_________________________________________________________________ - ############################################### - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return (((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) + if ((a = _filepath(f)) == "") { + ERRNO = "Filepath error `" f "'" + return "" } - - function _filenotexist(f, a) - { - #_________________________________________________________________ - ###################################### - if (f == "") { - return "" - } - if ((a = _filepath(f)) == "") { - ERRNO = "Filepath error `" f "'" - return "" - } - _cmd("if exist \"" a "\" exit 1 2>NUL") - if (_exitcode == 1) { - return (ERRNO = _NOP) - } + _cmd("if exist \"" a "\" exit 1 2>NUL") + if (_exitcode == 1) { return a } - - function _filepath(f, dd) - { - #_______________________________________________________________________ - ################################################ - if ((f = _filerdnehnd(f)) == "") { - return "" + ERRNO = "File not found `" f "'" + return _NOP +} + +#_______________________________________________________________________ +function _fn(f, p0, p1, p2) +{ + ################################################ + if (f in FUNCTAB) { + return @f(p0, p1, p2) + } +} + +#_______________________________________________________________________ +function _foreach(A, f, r, p0, p1, p2, i, p) +{ + #################################### + if (isarray(A)) { + _TMP0[p = _n()]["."] = 1 + _foreach_i0(A, f, _TMP0[p], p0, p1, p2) + return _th0(_retarr(_TMP0[p]), _tdel(p)) + } + if (_isptr(A)) { + _TMP0[p = _n()][_ARRLEN] = 1 + _tframe4("_foreach_i1" ((r ? "~" r : "")), A, f, _TMP0[p], p0, p1) + return _th0(_retarr(_TMP0[p]), _tdel(p)) + } +} + +#_____________________________________________________ +function _foreach_i0(A, f, D, p0, p1, p2) +{ + for (i in A) { + if (isarray(A[i])) { + _foreach_i0(A[i], f, D, p0, p1, p2) + } else { + _gen(D, @f(A[i], p0, p1, p2)) } - return (filegetrootdir(f, dd) ((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : ""))) } +} - function _filer(f, dd) - { - #_________________________________________________________________ - ############################################# - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILEROOT) { - return _FILEROOT[f] - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - return _FILEROOT[dd, f] - } - return (_FILEROOT[dd, f] = fileri(dd)) - } +#_____________________________________________________ +function _foreach_i1(p, f, D, p0, p1, p2) +{ + _gen(D, @f(p, p0, p1, p2)) +} - function _filerd(f, dd) - { - #_________________________________________________________________ - ############################################ - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return filegetrootdir(f, dd) +#_____________________________________________________________________________ +function _formatrexp(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /[\/\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATREXPESC[_FORMATSTRB[t]] } + return (_formatstrs0 _FORMATSTRA[t]) +} - function _filerdn(f, dd) - { - #_________________________________________________________________ - ########################################### - if ((f = _filerdnehnd(f)) == "") { - return "" - } - return ((f in _FILENAM ? filegetrootdir(f, dd) _FILENAM[f] : "")) - } +#___________________________________________________________ +function _formatrexp_init() +{ + _defescarr(_FORMATREXPESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATREXPESC, "\\/", "\\") + _FORMATREXPESC["\t"] = "\\t" +} - function _filerdne(f, dd) - { - #_________________________________________________________________ - ########################################## - if ((f = _filerdnehnd(f)) == "") { - return "" - } - if (f in _FILENAM) { - return (filegetrootdir(f, dd) _FILENAM[f] ((f in _FILEXT ? _FILEXT[f] : ""))) - } - if (f in _FILEXT) { - return (filegetrootdir(f, dd) _FILEXT[f]) - } - return "" +#_____________________________________________________________________________ +function _formatstrd(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /["\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRDESC[_FORMATSTRB[t]] } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _formatstrd_init() +{ + _defescarr(_FORMATSTRDESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATSTRDESC, "[\\\\\"]", "\\") + _FORMATSTRDESC["\t"] = "\\t" +} + +#__________________________________________________________________________________ +#################################################################################### + - function _filerdnehnd(st, c, r, d, n, A) - { - if (st) { - if ((c = toupper(st)) in _FILECACHE) { - #___________________________________________________________ - FLENGTH = length(st) - return _FILECACHE[c] - } - if (match(st, /^[ \t]*\\[ \t]*\\/)) { - if (match(substr(st, (FLENGTH = RLENGTH) + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { - FLENGTH = FLENGTH + RLENGTH - d = ((A[3] ? "\\" A[3] "$" : "")) A[4] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - _FILEDIRFL[c] - _FILEROOT[c] = r - } else { - FLENGTH = 0 - _filepath_err = "UNC" - return "" - } - } else { - match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) - if (! (FLENGTH = RLENGTH)) { - return "" - } - d = A[8] A[10] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, FLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - if (A[8]) { - _FILEDIRFL[c] - } - if (r) { - _FILEROOT[c] = r - } - } - if (n) { - if (match(n, /\.[^\.]*$/)) { - _FILEXT[c] = substr(n, RSTART) - _FILENAM[c] = substr(n, 1, RSTART - 1) - } else { - _FILENAM[c] = n - } - } - return c - } - return "" - } - function _filexist(f, a) - { - #_______________________________________________________________________ - ################################################ - if (f == "") { - return "" - } - if ((a = _filepath(f)) == "") { - ERRNO = "Filepath error `" f "'" - return "" - } - _cmd("if exist \"" a "\" exit 1 2>NUL") - if (_exitcode == 1) { - return a - } - ERRNO = "File not found `" f "'" - return _NOP - } - function _fn(f, p0, p1, p2) - { - #_______________________________________________________________________ - ################################################ - if (f in FUNCTAB) { - return @f(p0, p1, p2) - } +#___________________________________________________________________________________ +function _formatstrs(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRSESC[_FORMATSTRB[t]] } - - function _foreach(A, f, r, p0, p1, p2, i, p) - { - if (isarray(A)) { - #_______________________________________________________________________ - #################################### - _TMP0[p = _n()]["."] = 1 - _foreach_i0(A, f, _TMP0[p], p0, p1, p2) - return _th0(_retarr(_TMP0[p]), _tdel(p)) + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _formatstrs_init() +{ + _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) + _defescarr(_FORMATSTRSESC, "[\\\\']", "\\") + _FORMATSTRSESC["\t"] = "\\t" +} + +function _fpp(q, D, S) +{ + _conl() + _conline(q) + _conl() + q = _patharr0(S, q) + #_arregpath(D,S) + #_conl(_dumparr(D)) + _conl(_dumparr(S)) + _conl() + return q +} + +#_______________________________________________________________________ +######################################################################## + + + + + + + + + +function _fthru(A, c, p, B) +{ + return _fthru_i0(A, c, p, B, A[""]) +} + +#_________________________________________________________________ +function _fthru_i0(A, c, p, B, f) +{ + return ((f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : "")) +} + +function _gen(D, t) +{ + if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) { + D[++D[_ARRLEN]] = "" + } +} + +#_____________________________________________________________________________ +function _gensubfn(t, r, f, p0, A) +{ + ############################################### + if (match(t, r, A)) { + return (substr(t, 1, RSTART - 1) (@f(_th0(substr(t, RSTART, RLENGTH), t = substr(t, RSTART + RLENGTH)), A, p0)) _gensubfn(t, r, f, p0)) + } + return t +} + +#_____________________________________________________________________________ +function _get_errout(p) +{ + ####################################################### + return _tframe("_get_errout_i0", p) +} + +#_______________________________________________________________________ +function _get_errout_i0(p, t, n, a) +{ + return ((p in _tLOG ? _get_errout_i1(p) _get_errout_i3(p) : "")) +} + +#_________________________________________________________________ +function _get_errout_i1(p, t, n, a) +{ + if (p in _tLOG) { + n = "" + if (_tLOG[p]["TYPE"]) { + n = _tLOG[p]["TYPE"] ": " _get_errout_i2(p) + if (match(_tLOG[p]["TEXT"], /\x1F/)) { + t = n + gsub(/[^\t]/, " ", t) + return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) + } } - if (_isptr(A)) { - _TMP0[p = _n()][_ARRLEN] = 1 - _tframe4("_foreach_i1" ((r ? "~" r : "")), A, f, _TMP0[p], p0, p1) - return _th0(_retarr(_TMP0[p]), _tdel(p)) - } - } + return _ln(n _tLOG[p]["TEXT"]) + } +} + +#_______________________________________________________________________ +function _get_errout_i2(p) +{ + return (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) +} + +#_______________________________________________________________________ +function _get_errout_i3(p, t, ts, cl, cp, cr, a, b) +{ + if ("LSTR" in _tLOG[p]) { + t = _tLOG[p]["FULLSTR"] + ts = _tLOG[p]["TS"] + cp = "^" + if ("CSTR" in _tLOG[p]) { + cr = _tLOG[p]["CSTR"] + cl = _tLOG[p]["CLSTR"] + if ("CPSTR" in _tLOG[p]) { + cp = _tLOG[p]["CPSTR"] + } + } + cr = substr(cr, length(cl) + length(cp) + 1) + return (_ln(_tabtospc(t, ts)) _ln(_getchrln(" ", a = length(_tabtospc(_tLOG[p]["LSTR"], ts))) _getchrln("-", b = length(_tabtospc(cl, ts, a))) _getchrln("^", b = length(_tabtospc(cp, ts, a = a + b))) _getchrln("-", length(_tabtospc(cr, ts, a + b))))) + } +} - function _foreach_i0(A, f, D, p0, p1, p2) - { - for (i in A) { - #_____________________________________________________ - if (isarray(A[i])) { - _foreach_i0(A[i], f, D, p0, p1, p2) - } else { - _gen(D, @f(A[i], p0, p1, p2)) +#_____________________________________________________________________________ +function _get_logout(p) +{ + ####################################################### + return _tframe("_get_logout_i0", p) +} + +#_______________________________________________________________________ +function _get_logout_i0(p, t, n, a) +{ + if (p in _tLOG) { + n = (("DATE" in _tLOG[p] ? _tLOG[p]["DATE"] " " : "")) (("TIME" in _tLOG[p] ? _tLOG[p]["TIME"] " " : "")) + if (_tLOG[p]["TYPE"]) { + n = n _tLOG[p]["TYPE"] ": " (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) + if (match(_tLOG[p]["TEXT"], /\x1F/)) { + t = n + gsub(/[^\t]/, " ", t) + return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) + } + } + return _ln(n _tLOG[p]["TEXT"]) + } +} + +#_______________________________________________________________________ +function _getchrln(s, w) +{ + ################################################# + if (s == "") { + return + } + #if ( w!=w+0 || w<0 ) w=_CON_WIDTH + if (length(s) < w) { + if (s in _GETCHRLN) { + if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) { + return substr(_getchrlnt0, 1, w) } - } + } else { + _getchrlnt0 = s s + } + while (length(_getchrlnt0) < w) { + _getchrlnt0 = _getchrlnt0 _getchrlnt0 + } + _GETCHRLN[s] = _getchrlnt0 + return substr(_getchrlnt0, 1, w) + } else { + return substr(s, 1, w) + } +} + +#_______________________________________________________________________ +function _getdate() +{ + ##################################################### + return strftime("%F") +} + +#_____________________________________________________________________________ +function _getfilepath(t, f, al, b, A) +{ + ############################################ + ERRNO = "" + if (match(t, /^[ \t]*(("([^"]*)"[ \t]*)|([`']([^']*)'[ \t]*)|(([^ \t]+)[ \t]*))/, A)) { + al = RLENGTH + f = A[3] A[5] A[7] + _conl("_getfilepath(" f ") (" al ")") + if (b = _filepath(f)) { + if (length(f) <= FLENGTH) { + FLENGTH = al + return b + } + ERRNO = "Filepath `" f "' error" + } + } + FLENGTH = 0 +} + +function _getfilever(f) +{ + ############################################################# + split(_cmd(_fileverpath " \"" f "\""), _GETFILEVERA0, /[ \t]+/) + if (_GETFILEVERA0[5]) { + return _GETFILEVERA0[5] + } +} + +#_________________________________________________________________ +function _getime() +{ + ################################################ + return strftime("%H:%M:%S") +} + +#_________________________________________________________________ +function _getmpdir(f, dd) +{ + ########################################## + if (! dd || ! (dd = _filerd(dd))) { + dd = _FILEIO_TMPRD + } + if (f = (f ? _filerd(f, dd) : _filerd("_" ++_FILEIO_TMPCNTR "\\", dd))) { + _FILEIO_RDTMP[toupper(f)] + } + return f +} + +#_________________________________________________________________ +function _getmpfile(f, dd) +{ + ######################################### + if (! dd || ! (dd = _filerd(dd))) { + dd = _FILEIO_TMPRD + } + if (f = _filerdne((_filene(f) ? f : f "_" ++_FILEIO_TMPCNTR), dd)) { + _FILEIO_RDNETMP[toupper(f)] + } + return f +} + +#_______________________________________________________________________ +function _getperf(o, t, a) +{ + ############################################### + (o == "" ? ++_getperf_opcurr : _getperf_opcurr = o) + if ((a = _getsecond()) != _getperf_last) { + _getperf_opsec = (_getperf_opcurr - _getperf_opstart) / ((_getperf_last = a) - _getperf_start) + return @_getperf_fn(o, t, a) + } + return 1 +} + +#___________________________________________________________ +function _getperf_(o, t, a) +{ + if (a >= _getperf_end) { + return 0 } - - function _foreach_i1(p, f, D, p0, p1, p2) - { - #_____________________________________________________ - _gen(D, @f(p, p0, p1, p2)) + if (_getperf_opsecp != _getperf_opsec) { + _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") + _getperf_stat = _constatstr + } + return 1 +} + +#___________________________________________________________ +function _getperf_noe(o, t, a) +{ + if (_getperf_opsecp != _getperf_opsec) { + _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") + _getperf_stat = _constatstr + } + return 1 +} + +#___________________________________________________________ +function _getperf_noenot(o, t, a) +{ + return 1 +} + +#___________________________________________________________ +function _getperf_not(o, t, a) +{ + if (a < _getperf_end) { + return 1 } +} - function _formatrexp(t) - { - #_____________________________________________________________________________ - _formatstrq0 = split(t, _FORMATSTRA, /[\/\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATREXPESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } +#_________________________________________________________________________________________ +########################################################################################## - function _formatrexp_init() - { - #___________________________________________________________ - _defescarr(_FORMATREXPESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATREXPESC, "\\/", "\\") - _FORMATREXPESC["\t"] = "\\t" - } - function _formatstrd(t) - { - #_____________________________________________________________________________ - _formatstrq0 = split(t, _FORMATSTRA, /["\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRDESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _formatstrd_init() - { - #___________________________________________________________ - _defescarr(_FORMATSTRDESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATSTRDESC, "[\\\\\"]", "\\") - _FORMATSTRDESC["\t"] = "\\t" - } - function _formatstrs(t) - { - #__________________________________________________________________________________ - #################################################################################### - #___________________________________________________________________________________ - _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRSESC[_FORMATSTRB[t]] - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _formatstrs_init() - { - #___________________________________________________________ - _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC) - _defescarr(_FORMATSTRSESC, "[\\\\']", "\\") - _FORMATSTRSESC["\t"] = "\\t" - } - function _fpp(q, D, S) - { - _conl() - _conline(q) - _conl() - #_arregpath(D,S) - #_conl(_dumparr(D)) - q = _patharr0(S, q) - _conl(_dumparr(S)) - _conl() - return q - } - function _fthru(A, c, p, B) - { - #_______________________________________________________________________ - ######################################################################## - return _fthru_i0(A, c, p, B, A[""]) - } - function _fthru_i0(A, c, p, B, f) - { - #_________________________________________________________________ - return ((f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : "")) - } - function _gen(D, t) - { - if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) { - D[++D[_ARRLEN]] = "" - } - } - function _gensubfn(t, r, f, p0, A) - { - #_____________________________________________________________________________ - ############################################### - if (match(t, r, A)) { - return (substr(t, 1, RSTART - 1) (@f(_th0(substr(t, RSTART, RLENGTH), t = substr(t, RSTART + RLENGTH)), A, p0)) _gensubfn(t, r, f, p0)) - } - return t - } - function _get_errout(p) - { - #_____________________________________________________________________________ - ####################################################### - return _tframe("_get_errout_i0", p) - } - function _get_errout_i0(p, t, n, a) - { - #_______________________________________________________________________ - return ((p in _tLOG ? _get_errout_i1(p) _get_errout_i3(p) : "")) - } - - function _get_errout_i1(p, t, n, a) - { - if (p in _tLOG) { - #_________________________________________________________________ - n = "" - if (_tLOG[p]["TYPE"]) { - n = _tLOG[p]["TYPE"] ": " _get_errout_i2(p) - if (match(_tLOG[p]["TEXT"], /\x1F/)) { - t = n - gsub(/[^\t]/, " ", t) - return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) - } - } - return _ln(n _tLOG[p]["TEXT"]) - } - } - function _get_errout_i2(p) - { - #_______________________________________________________________________ - return (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) - } - - function _get_errout_i3(p, t, ts, cl, cp, cr, a, b) - { - if ("LSTR" in _tLOG[p]) { - #_______________________________________________________________________ - t = _tLOG[p]["FULLSTR"] - ts = _tLOG[p]["TS"] - cp = "^" - if ("CSTR" in _tLOG[p]) { - cr = _tLOG[p]["CSTR"] - cl = _tLOG[p]["CLSTR"] - if ("CPSTR" in _tLOG[p]) { - cp = _tLOG[p]["CPSTR"] - } - } - cr = substr(cr, length(cl) + length(cp) + 1) - return (_ln(_tabtospc(t, ts)) _ln(_getchrln(" ", a = length(_tabtospc(_tLOG[p]["LSTR"], ts))) _getchrln("-", b = length(_tabtospc(cl, ts, a))) _getchrln("^", b = length(_tabtospc(cp, ts, a = a + b))) _getchrln("-", length(_tabtospc(cr, ts, a + b))))) - } - } - function _get_logout(p) - { - #_____________________________________________________________________________ - ####################################################### - return _tframe("_get_logout_i0", p) - } - function _get_logout_i0(p, t, n, a) - { - if (p in _tLOG) { - #_______________________________________________________________________ - n = (("DATE" in _tLOG[p] ? _tLOG[p]["DATE"] " " : "")) (("TIME" in _tLOG[p] ? _tLOG[p]["TIME"] " " : "")) - if (_tLOG[p]["TYPE"]) { - n = n _tLOG[p]["TYPE"] ": " (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : "")) - if (match(_tLOG[p]["TEXT"], /\x1F/)) { - t = n - gsub(/[^\t]/, " ", t) - return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1))) - } - } - return _ln(n _tLOG[p]["TEXT"]) - } - } - function _getchrln(s, w) - { - #_______________________________________________________________________ - ################################################# - #if ( w!=w+0 || w<0 ) w=_CON_WIDTH - if (s == "") { - return - } - if (length(s) < w) { - if (s in _GETCHRLN) { - if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) { - return substr(_getchrlnt0, 1, w) - } - } else { - _getchrlnt0 = s s - } - while (length(_getchrlnt0) < w) { - _getchrlnt0 = _getchrlnt0 _getchrlnt0 - } - _GETCHRLN[s] = _getchrlnt0 - return substr(_getchrlnt0, 1, w) - } else { - return substr(s, 1, w) - } - } - function _getdate() - { - #_______________________________________________________________________ - ##################################################### - return strftime("%F") - } - function _getfilepath(t, f, al, b, A) - { - #_____________________________________________________________________________ - ############################################ - ERRNO = "" - if (match(t, /^[ \t]*(("([^"]*)"[ \t]*)|([`']([^']*)'[ \t]*)|(([^ \t]+)[ \t]*))/, A)) { - al = RLENGTH - f = A[3] A[5] A[7] - _conl("_getfilepath(" f ") (" al ")") - if (b = _filepath(f)) { - if (length(f) <= FLENGTH) { - FLENGTH = al - return b - } - ERRNO = "Filepath `" f "' error" + + + +function _getreg_i1(D, r, R, a, i, il, ir, rc, B) +{ + a = IGNORECASE + IGNORECASE = 1 + r = "^" _torexp(r) + rc = 0 + zs = "" + for (i in R) { + if (match(i, r, B)) { + il = B[_torexp_pfxcntr] + ir = gensub(/....$/, "", 1, substr(i, 1 + B[_torexp_pfxcntr, "length"])) + if (! gsub(/^\\/, "", ir) && match(il, /[^\\]+$/)) { + ir = substr(il, RSTART) ir } + D[ir] = R[i] + rc++ } - FLENGTH = 0 } - - function _getfilever(f) - { - ############################################################# - split(_cmd(_fileverpath " \"" f "\""), _GETFILEVERA0, /[ \t]+/) - if (_GETFILEVERA0[5]) { - return _GETFILEVERA0[5] - } + IGNORECASE = a + if (rc > 0) { + return rc } +} - function _getime() - { - #_________________________________________________________________ - ################################################ - return strftime("%H:%M:%S") - } +#_________________________________________________________________ +function _getsecond() +{ + ############################################# + return systime() +} - function _getmpdir(f, dd) - { - #_________________________________________________________________ - ########################################## - if (! dd || ! (dd = _filerd(dd))) { - dd = _FILEIO_TMPRD - } - if (f = (f ? _filerd(f, dd) : _filerd("_" ++_FILEIO_TMPCNTR "\\", dd))) { - _FILEIO_RDTMP[toupper(f)] - } - return f +#___________________________________________________________ +function _getsecondsync(a, c, b, c2) +{ + ########################## + a = systime() + while (a == systime()) { + ++c } + return (a + 1) +} - function _getmpfile(f, dd) - { - #_________________________________________________________________ - ######################################### - if (! dd || ! (dd = _filerd(dd))) { - dd = _FILEIO_TMPRD +#_______________________________________________________________________ +function _getuid(p) +{ + ################################################# 1 # + if (p in _UIDOBL) { + for (_tptr in _UIDOBLV[_getuida0 = _UIDOBL[p]]) { + delete _UIDOBLV[_getuida0][_tptr] + _CLASSPTR[_tptr] = p + return _tptr } - if (f = _filerdne((_filene(f) ? f : f "_" ++_FILEIO_TMPCNTR), dd)) { - _FILEIO_RDNETMP[toupper(f)] - } - return f } + _CLASSPTR[_tptr = _UIDPFX[p] _getuid_i0(_UIDCNT[p], _UIDCHRL[_tptr = _UIDCHR[p]], _UIDCHRH[_tptr]) _UIDSFX[p]] = p + return _tptr +} - function _getperf(o, t, a) - { - #_______________________________________________________________________ - ############################################### - (o == "" ? ++_getperf_opcurr : _getperf_opcurr = o) - if ((a = _getsecond()) != _getperf_last) { - _getperf_opsec = (_getperf_opcurr - _getperf_opstart) / ((_getperf_last = a) - _getperf_start) - return @_getperf_fn(o, t, a) +#_____________________________________________________ +function _getuid_i0(p, UL, UH) +{ + if ("" == (_tptr = UL[_UIDCNTL[p]])) { + for (_tptr in UH) { + delete UH[_tptr] + return ((_UIDCNTH[p] = _tptr) (_UIDCNTL[p] = UL[""])) } - return 1 + _fatal("out of UID") } + return (_UIDCNTH[p] (_UIDCNTL[p] = _tptr)) +} - function _getperf_(o, t, a) - { - #___________________________________________________________ - if (a >= _getperf_end) { - return 0 - } - if (_getperf_opsecp != _getperf_opsec) { - _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") - _getperf_stat = _constatstr - } - return 1 - } +function _handle8494(t) +{ + return gensub(/(.)/, ".\\1", "G", t) +} - function _getperf_noe(o, t, a) - { - if (_getperf_opsecp != _getperf_opsec) { - #___________________________________________________________ - _constat(((_constatstr == _getperf_stat ? _getperf_statstr : _getperf_statstr = _constatstr)) t " [TIME=" (a - _getperf_start) " sec(" (_getperf_opsecp = _getperf_opsec) " ops/sec)]") - _getperf_stat = _constatstr - } - return 1 +#_____________________________________________________________________________ +function _hexnum(n, l) +{ + ######################################################### + if (l + 0 < 1) { + l = 2 } + return sprintf("%." ((l + 0 < 1 ? 2 : l)) "X", n) +} - function _getperf_noenot(o, t, a) - { - #___________________________________________________________ - return 1 +#_________________________________________________________________ +function _igetperf(t, s, o) +{ + ######################################### # t-test period in seconds(==0 ? no period; s(=true/false)-output/not output status; o-qnt of ops before test start + if (t == 0 && t == "" && s == 0 && s == "" && o == 0 && o == "") { + if (_getperf_fn !~ /not$/ && _constatstr == _getperf_stat) { + _constat(_getperf_statstr) + } + _getperf_fn = "_nop" + return ("[TIME=" (_getperf_last - _getperf_start) " sec(" _getperf_opsec " ops/sec)]") + } + _conl("initiate _getperf") + _getperf_opstart = _getperf_opcurr = o + 0 + _getperf_opsec = _getperf_opsecp = _getperf_stat = _getperf_statstr = "" + _getperf_end = t + (_getperf_start = _getperf_last = _getsecondsync()) + _getperf_fn = ((t + 0 > 0 ? "_getperf_" : "_getperf_noe")) ((s ? "" : "not")) + return _getperf_start +} + +function _import_data(t, p, p2, a) +{ + if (match(t, /^_DATA: /)) { + _tDATA[a = _wLCHLD(p, _N())][""] + delete _tDATA[a][""] + _Zimparr(_tDATA[a], substr(t, 8)) + _conl("DATA: `" _tDATA[a]["ID"] "':`" _tDATA[a]["DATA"] "'") + return "" } - - function _getperf_not(o, t, a) - { - #___________________________________________________________ - if (a < _getperf_end) { - return 1 + return t +} + +#_______________________________________________________________________ +function _info(t, d, A) +{ + ################################################## + if (_ERRLOG_IF) { + A["TYPE"] = "INFO" + A["TEXT"] = t + _log(A, d) + } +} + +# test with the different path types +# _conl(_ln("SRC:") _dumparr(S)); _conl(); + +function _ini(p, cs, dptr, pfx, sfx, hstr, lstr) +{ + return _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) +} + +function _initfilever() +{ + _fileverpath = "\\\\CPU\\eGAWK\\LIB\\_filever\\_filever.exe" +} + +function _initrdreg() +{ + _RDREGTYPE["SZ"] = "STR" + _RDREGTYPE["DWORD"] = "W32" + _RDREGTYPE["QWORD"] = "W64" + _RDREGTYPE["BINARY"] = "BIN" + _RDREGTYPE["EXPAND_SZ"] = "XSZ" + _RDREGTYPE["MULTI_SZ"] = "MSZ" + _RDrdregfld = _rdregkey = 0 +} + +function _initregpath0() +{ + _REGPATH0REGDIR[""] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKLM"] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKEY_LOCAL_MACHINE"] = "HKEY_LOCAL_MACHINE" + _REGPATH0REGDIR["HKCR"] = "HKEY_CLASSES_ROOT" + _REGPATH0REGDIR["HKEY_CLASSES_ROOT"] = "HKEY_CLASSES_ROOT" + _REGPATH0REGDIR["HKCU"] = "HKEY_CURRENT_USER" + _REGPATH0REGDIR["HKEY_CURRENT_USER"] = "HKEY_CURRENT_USER" + _REGPATH0REGDIR["HKU"] = "HKEY_USERS" + _REGPATH0REGDIR["HKEY_USERS"] = "HKEY_USERS" + _REGPATH0REGDIR["HKCC"] = "HKEY_CURRENT_CONFIG" + _REGPATH0REGDIR["HKEY_CURRENT_CONFIG"] = "HKEY_CURRENT_CONFIG" + _REGPATH0REGDIR["HKPD"] = "HKEY_PERFORMANCE_DATA" + _REGPATH0REGDIR["HKEY_PERFORMANCE_DATA"] = "HKEY_PERFORMANCE_DATA" +} + +function _initshare() +{ + _sharextool = "\\\\CPU\\eGAWK\\LIB\\_share\\_share.exe" +} + +#_________________________________________ +function _initspecialuid() +{ + _NOINDEX = _getuid() + _LEN = _getuid() + _PTR = _getuid() + _NAME = _getuid() + _TYPE = _getuid() + _FORMAT = _getuid() +} + +function _initsys() +{ +} + +#_______________________________________________________________________ +function _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) +{ + ################### 1 # + if (cs == 0 && cs == "") { + cs = p + p = _getuid() + } + _conl() + _conl() + _conl(cs) + if (match(cs, /^(([^:]*):)?(([^'\xB4]*\xB4.)*[^'\xB4]*)[']/, A)) { + pfx = A[3] + dptr = A[2] + } + if (match(cs = substr(cs, 1 + RLENGTH), /'(([^'\xB4]*\xB4.)*[^'\xB4]*)$/, A)) { + sfx = A[1] + cs = substr(cs, 1, RSTART - 1) + } + if (match(cs, /^(([`\^])(.*))/, A)) { + if (A[2] == "`") { + hstr = A[3] "~" + lstr = "" + } else { + lstr = A[3] "+" + hstr = "" + } + } else { + if (match(cs, /^(([^'\xB4\|]*\xB4.)*[^'\xB4\|]*)(\|(.*))?/, A)) { + hstr = A[1] + lstr = A[4] + } else { + ERRNO = "_inituid(): bad parameters" + return } } - - function _getreg_i1(D, r, R, a, i, il, ir, rc, B) - { - #_________________________________________________________________________________________ - ########################################################################################## - a = IGNORECASE - IGNORECASE = 1 - r = "^" _torexp(r) - rc = 0 - zs = "" - for (i in R) { - if (match(i, r, B)) { - il = B[_torexp_pfxcntr] - ir = gensub(/....$/, "", 1, substr(i, 1 + B[_torexp_pfxcntr, "length"])) - if (! gsub(/^\\/, "", ir) && match(il, /[^\\]+$/)) { - ir = substr(il, RSTART) ir + _conl(dptr ":" pfx "'" hstr "|" lstr "'" sfx) + return _cfguid(p, dptr, pfx, sfx, hstr, lstr) +} + +function _inituidefault(h, l, H, L) +{ + _classys = "" + delete _UIDOBLV[_UIDOBLV[_UIDOBL[_classys] = _classys][""] = _classys][""] + _UIDPFX[_classys] + _UIDSFX[_classys] + _UIDCNT[_classys] = _UIDCHR[_classys] = _CLASSPTR[_classys] = _classys + h = "AB" + l = h "01" + _splitstr(H, h) + _splitstr(L, l) + delete _UIDCHRH[_UIDCHRH[_classys][""] = _classys][""] + delete _UIDCHRL[_UIDCHRL[_classys][""] = _classys][""] + _UIDCNTH[_classys] + _cfguidh(_classys, H, L) + _UIDCNTL[_classys] = _cfguidl(_classys, L, L) + _CLASSFN[_classys]["del"] = "_tobjDEL" + _CLASSFN[_classys]["new"] = "_tobjNEW" + _drawuid(_classys) + _initspecialuid() +} + +#_______________________________________________________________________ +function _ins(S, sf, D, df) +{ + ################################################ + if (sf in S) { + if (isarray(S[sf])) { + if (df in D) { + if (isarray(D[df])) { + return _extarr(D[df], S[sf]) } - D[ir] = R[i] - rc++ + delete D[df] } - } - IGNORECASE = a - if (rc > 0) { - return rc - } + D[df][""] + delete D[df][""] + return _extarr(D[df], S[sf]) + } else { + if (isarray(D[df])) { + delete D[df] + } + D[df] = S[sf] D[df] + } + } +} + +#_________________________________________________________________ +function _insf(A, f) +{ + ############################################### + A["F"][""] = A["B"][A["F"][f] = A["F"][""]] = f +} + +#_________________________________________________________________ +function _insframe(A, f) +{ + ########################################### + A[f] = A[""] + A[""] = f +} + +######################## +#_________________________________________________________________ +function _inspass(A, f) +{ + A[f] = A[""] + A[""] = f +} + +# there is problem with string's format: i can;t easilly merge 2 charsets: comma-divided and every-char-divided strings + +#_______________________________________________________________________ +function _isptr(p) +{ + ################################################## 1 # + if (isarray(p)) { + is = _NOP + it = "A" + return 0 } - - function _getsecond() - { - #_________________________________________________________________ - ############################################# - return systime() + is = p + if (p == 0 && p == "") { + it = "-" + return 0 } - - function _getsecondsync(a, c, b, c2) - { - #___________________________________________________________ - ########################## - a = systime() - while (a == systime()) { - ++c - } - return (a + 1) - } - - function _getuid(p) - { - if (p in _UIDOBL) { - for (_tptr in _UIDOBLV[_getuida0 = _UIDOBL[p]]) { - #_______________________________________________________________________ - ################################################# 1 # - delete _UIDOBLV[_getuida0][_tptr] - _CLASSPTR[_tptr] = p - return _tptr - } - } - _CLASSPTR[_tptr = _UIDPFX[p] _getuid_i0(_UIDCNT[p], _UIDCHRL[_tptr = _UIDCHR[p]], _UIDCHRH[_tptr]) _UIDSFX[p]] = p - return _tptr + if (p in _CLASSPTR) { + return (it = "P") } + it = "S" + return 0 +} - function _getuid_i0(p, UL, UH) - { - if ("" == (_tptr = UL[_UIDCNTL[p]])) { - for (_tptr in UH) { - #_____________________________________________________ - delete UH[_tptr] - return ((_UIDCNTH[p] = _tptr) (_UIDCNTL[p] = UL[""])) - } - _fatal("out of UID") - } - return (_UIDCNTH[p] (_UIDCNTL[p] = _tptr)) +#_______________________________________________________________________ +function _istr(p) +{ + ################################################### 1 # + if (isarray(p)) { + is = _NOP + it = "A" + return 0 } - - function _handle8494(t) - { - return gensub(/(.)/, ".\\1", "G", t) + is = p + if (p == 0 && p == "") { + it = "-" + return 0 } - - function _hexnum(n, l) - { - #_____________________________________________________________________________ - ######################################################### - if (l + 0 < 1) { - l = 2 + return (it = (p == "" ? "s" : "S")) +} + +#_________________________________________________________________ +function _lengthsort(i1, v1, i2, v2) +{ + ############################## + return ((length(i1) < length(i2) ? -1 : (length(i1) > length(i2) ? 1 : (i1 < i2 ? -1 : 1)))) +} + +#_________________________________________________________________ +function _lib_APPLY() +{ + return _ffaccr(_LIBAPI, "_lib_APPLY") +} + +#_________________________________________________________________ +function _lib_BEGIN(A) +{ + return _ffaccr(_LIBAPI, "_lib_BEGIN", "", A) +} + +#_______________________________________________________________________ +function _lib_CMDLN(t) +{ + return _pass(_LIBAPI["F"], "_lib_CMDLN", t) +} + +#_________________________________________________________________ +function _lib_END(A) +{ + return _ffaccr(_LIBAPI, "_lib_END", "", A) +} + +#_________________________________________________________________ +function _lib_HELP() +{ + return _fbaccr(_LIBAPI, "_lib_HELP") +} + +#_________________________________________________________________ +function _lib_NAMEVER() +{ + return _fbaccr(_LIBAPI, "_lib_NAMEVER") +} + +#_____________________________________________________________________________ +function _ln(t) +{ + ############################################################### + return ((t ~ /\x0A$/ ? t : t _CHR["EOL"])) +} + +#_________________________________________________________________ +function _log(A, p, a, B) +{ + ########################################### + if (isarray(A)) { + A["TIME"] = _getime() + A["DATE"] = _getdate() + if (p) { + _tLOG[p = _wLCHLD(p, _N())][""] + delete _tLOG[p][""] + _movarr(_tLOG[p], A) + return p } - return sprintf("%." ((l + 0 < 1 ? 2 : l)) "X", n) + _expout("_ERRLOG: " _Zexparr(A) "\n") + } else { + B["TEXT"] = A + B["TYPE"] = "" + return _log(B, p) } +} - function _igetperf(t, s, o) - { - if (t == 0 && t == "" && s == 0 && s == "" && o == 0 && o == "") { - #_________________________________________________________________ - ######################################### # t-test period in seconds(==0 ? no period; s(=true/false)-output/not output status; o-qnt of ops before test start - if (_getperf_fn !~ /not$/ && _constatstr == _getperf_stat) { - _constat(_getperf_statstr) +#_________________________________________________________________ +function _lspctab(t, ts, l, l1, l2, A) +{ + ################################ + while (match(t, /^(\t*)( *)((\t*)(.*))$/, A)) { + if (A[1, "length"] >= l) { + return substr(t, l + 1) + } + if (A[2]) { + if ((l1 = int(A[2, "length"] / ts)) >= (l2 = l - A[1, "length"])) { + return (substr(A[2], l2 * ts + 1) A[3]) } - _getperf_fn = "_nop" - return ("[TIME=" (_getperf_last - _getperf_start) " sec(" _getperf_opsec " ops/sec)]") - } - _conl("initiate _getperf") - _getperf_opstart = _getperf_opcurr = o + 0 - _getperf_opsec = _getperf_opsecp = _getperf_stat = _getperf_statstr = "" - _getperf_end = t + (_getperf_start = _getperf_last = _getsecondsync()) - _getperf_fn = ((t + 0 > 0 ? "_getperf_" : "_getperf_noe")) ((s ? "" : "not")) - return _getperf_start - } - - function _import_data(t, p, p2, a) - { - if (match(t, /^_DATA: /)) { - _tDATA[a = _wLCHLD(p, _N())][""] - delete _tDATA[a][""] - _Zimparr(_tDATA[a], substr(t, 8)) - _conl("DATA: `" _tDATA[a]["ID"] "':`" _tDATA[a]["DATA"] "'") - return "" + if (! A[4]) { + return A[5] + } + t = A[1] _getchrln("\t", l1) A[3] + } else { + return t } - return t } - - function _info(t, d, A) - { - if (_ERRLOG_IF) { - #_______________________________________________________________________ - ################################################## - A["TYPE"] = "INFO" - A["TEXT"] = t - _log(A, d) - } +} + +function _mac_init() +{ + _MACPFX["\204"] = "_macpfx84" + _MACPFX[""] = "_mpupfxsubret" + _MACPFX84SFX["\204"] = "_macpfx84" + _MACPFX84SFX["\224"] = "_macsfx94" + _MACPFX84SFX[""] = "_mpusfxsubret" + _VLDMAXSTRING = 1e+06 +} + +function _macpfx84(F, D, C, p1, p2, p3) +{ + return _mpusub(_MACPFX84SFX, D, C, D[_mpuptr++], p1, p2, p3) +} + +function _macsfx94(F, D, C, p1, p2, p3) +{ + return _mpuretsub(D, _handle8494(_mpuacc)) +} + +#_______________________________________________________________________ +function _movarr(D, S) +{ + ################################################### + delete D + D[""] + delete D[""] + _addarr(D, S) +} + +function _mpu(t, F, p1, p2, p3, D, C) +{ + if (patsplit(t, C, /[\x84\x93\x94]/, D) > 0) { + _conline("CODE") + _conl() + _conl(_dumparr(C)) + _conline("DATA") + _conl() + _conl(_dumparr(D)) + _mpuptr = 0 + _mpucc0 = "" + _mpusub(F, D, C, D[_mpuptr++], p1, p2, p3) + return _mpuacc } + return t +} - function _ini(p, cs, dptr, pfx, sfx, hstr, lstr) - { - # test with the different path types - # _conl(_ln("SRC:") _dumparr(S)); _conl(); - return _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) - } +# +# /rexpstr/ -> datastr +# (\x00\t\+)* -> 28 00 09 5B 2B 29 +# +# unesc all non-rexp characters: replace unesc of rexp-characters but do not remove it: \* -> \*, \x2A -> \*, \052 -> \*, \\ -> \# - function _initfilever() - { - _fileverpath = "\\\\CPU\\eGAWK\\LIB\\_filever\\_filever.exe" - } - function _initrdreg() - { - _RDREGTYPE["SZ"] = "STR" - _RDREGTYPE["DWORD"] = "W32" - _RDREGTYPE["QWORD"] = "W64" - _RDREGTYPE["BINARY"] = "BIN" - _RDREGTYPE["EXPAND_SZ"] = "XSZ" - _RDREGTYPE["MULTI_SZ"] = "MSZ" - _RDrdregfld = _rdregkey = 0 - } - function _initregpath0() - { - _REGPATH0REGDIR[""] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKLM"] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKEY_LOCAL_MACHINE"] = "HKEY_LOCAL_MACHINE" - _REGPATH0REGDIR["HKCR"] = "HKEY_CLASSES_ROOT" - _REGPATH0REGDIR["HKEY_CLASSES_ROOT"] = "HKEY_CLASSES_ROOT" - _REGPATH0REGDIR["HKCU"] = "HKEY_CURRENT_USER" - _REGPATH0REGDIR["HKEY_CURRENT_USER"] = "HKEY_CURRENT_USER" - _REGPATH0REGDIR["HKU"] = "HKEY_USERS" - _REGPATH0REGDIR["HKEY_USERS"] = "HKEY_USERS" - _REGPATH0REGDIR["HKCC"] = "HKEY_CURRENT_CONFIG" - _REGPATH0REGDIR["HKEY_CURRENT_CONFIG"] = "HKEY_CURRENT_CONFIG" - _REGPATH0REGDIR["HKPD"] = "HKEY_PERFORMANCE_DATA" - _REGPATH0REGDIR["HKEY_PERFORMANCE_DATA"] = "HKEY_PERFORMANCE_DATA" - } - function _initshare() - { - _sharextool = "\\\\CPU\\eGAWK\\LIB\\_share\\_share.exe" - } - function _initspecialuid() - { - #_________________________________________ - _NOINDEX = _getuid() - _LEN = _getuid() - _PTR = _getuid() - _NAME = _getuid() - _TYPE = _getuid() - _FORMAT = _getuid() - } - function _initsys() - { - } - function _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A) - { - if (cs == 0 && cs == "") { - #_______________________________________________________________________ - ################### 1 # - cs = p - p = _getuid() - } - _conl() - _conl() - _conl(cs) - if (match(cs, /^(([^:]*):)?(([^'\xB4]*\xB4.)*[^'\xB4]*)[']/, A)) { - pfx = A[3] - dptr = A[2] - } - if (match(cs = substr(cs, 1 + RLENGTH), /'(([^'\xB4]*\xB4.)*[^'\xB4]*)$/, A)) { - sfx = A[1] - cs = substr(cs, 1, RSTART - 1) - } - if (match(cs, /^(([`\^])(.*))/, A)) { - if (A[2] == "`") { - hstr = A[3] "~" - lstr = "" - } else { - lstr = A[3] "+" - hstr = "" - } - } else { - if (match(cs, /^(([^'\xB4\|]*\xB4.)*[^'\xB4\|]*)(\|(.*))?/, A)) { - hstr = A[1] - lstr = A[4] - } else { - ERRNO = "_inituid(): bad parameters" - return - } - } - _conl(dptr ":" pfx "'" hstr "|" lstr "'" sfx) - return _cfguid(p, dptr, pfx, sfx, hstr, lstr) - } - - function _inituidefault(h, l, H, L) - { - _classys = "" - delete _UIDOBLV[_UIDOBLV[_UIDOBL[_classys] = _classys][""] = _classys][""] - _UIDPFX[_classys] - _UIDSFX[_classys] - _UIDCNT[_classys] = _UIDCHR[_classys] = _CLASSPTR[_classys] = _classys - h = "AB" - l = h "01" - _splitstr(H, h) - _splitstr(L, l) - delete _UIDCHRH[_UIDCHRH[_classys][""] = _classys][""] - delete _UIDCHRL[_UIDCHRL[_classys][""] = _classys][""] - _UIDCNTH[_classys] - _cfguidh(_classys, H, L) - _UIDCNTL[_classys] = _cfguidl(_classys, L, L) - _CLASSFN[_classys]["del"] = "_tobjDEL" - _CLASSFN[_classys]["new"] = "_tobjNEW" - _drawuid(_classys) - _initspecialuid() - } - - function _ins(S, sf, D, df) - { - if (sf in S) { - if (isarray(S[sf])) { - if (df in D) { - #_______________________________________________________________________ - ################################################ - if (isarray(D[df])) { - return _extarr(D[df], S[sf]) - } - delete D[df] - } - D[df][""] - delete D[df][""] - return _extarr(D[df], S[sf]) - } else { - if (isarray(D[df])) { - delete D[df] - } - D[df] = S[sf] D[df] - } - } - } - function _insf(A, f) - { - #_________________________________________________________________ - ############################################### - A["F"][""] = A["B"][A["F"][f] = A["F"][""]] = f - } - function _insframe(A, f) - { - #_________________________________________________________________ - ########################################### - A[f] = A[""] - A[""] = f - } - function _inspass(A, f) - { - ######################## - #_________________________________________________________________ - A[f] = A[""] - A[""] = f - } - function _isptr(p) - { - if (isarray(p)) { - # there is problem with string's format: i can;t easilly merge 2 charsets: comma-divided and every-char-divided strings - #_______________________________________________________________________ - ################################################## 1 # - is = _NOP - it = "A" - return 0 - } - is = p - if (p == 0 && p == "") { - it = "-" - return 0 - } - if (p in _CLASSPTR) { - return (it = "P") - } - it = "S" - return 0 - } - function _istr(p) - { - if (isarray(p)) { - #_______________________________________________________________________ - ################################################### 1 # - is = _NOP - it = "A" - return 0 - } - is = p - if (p == 0 && p == "") { - it = "-" - return 0 - } - return (it = (p == "" ? "s" : "S")) - } - function _lengthsort(i1, v1, i2, v2) - { - #_________________________________________________________________ - ############################## - return ((length(i1) < length(i2) ? -1 : (length(i1) > length(i2) ? 1 : (i1 < i2 ? -1 : 1)))) - } - function _lib_APPLY() - { - #_________________________________________________________________ - return _ffaccr(_LIBAPI, "_lib_APPLY") - } - function _lib_BEGIN(A) - { - #_________________________________________________________________ - return _ffaccr(_LIBAPI, "_lib_BEGIN", "", A) - } - function _lib_CMDLN(t) - { - #_______________________________________________________________________ - return _pass(_LIBAPI["F"], "_lib_CMDLN", t) - } - function _lib_END(A) - { - #_________________________________________________________________ - return _ffaccr(_LIBAPI, "_lib_END", "", A) - } - function _lib_HELP() - { - #_________________________________________________________________ - return _fbaccr(_LIBAPI, "_lib_HELP") - } - function _lib_NAMEVER() - { - #_________________________________________________________________ - return _fbaccr(_LIBAPI, "_lib_NAMEVER") - } - function _ln(t) - { - #_____________________________________________________________________________ - ############################################################### - return ((t ~ /\x0A$/ ? t : t _CHR["EOL"])) - } - function _log(A, p, a, B) - { - if (isarray(A)) { - #_________________________________________________________________ - ########################################### - A["TIME"] = _getime() - A["DATE"] = _getdate() - if (p) { - _tLOG[p = _wLCHLD(p, _N())][""] - delete _tLOG[p][""] - _movarr(_tLOG[p], A) - return p - } - _expout("_ERRLOG: " _Zexparr(A) "\n") - } else { - B["TEXT"] = A - B["TYPE"] = "" - return _log(B, p) - } - } - function _lspctab(t, ts, l, l1, l2, A) - { - while (match(t, /^(\t*)( *)((\t*)(.*))$/, A)) { - #_________________________________________________________________ - ################################ - if (A[1, "length"] >= l) { - return substr(t, l + 1) - } - if (A[2]) { - if ((l1 = int(A[2, "length"] / ts)) >= (l2 = l - A[1, "length"])) { - return (substr(A[2], l2 * ts + 1) A[3]) - } - if (! A[4]) { - return A[5] - } - t = A[1] _getchrln("\t", l1) A[3] - } else { - return t - } - } - } - function _mac_init() - { - _MACPFX["\204"] = "_macpfx84" - _MACPFX[""] = "_mpupfxsubret" - _MACPFX84SFX["\204"] = "_macpfx84" - _MACPFX84SFX["\224"] = "_macsfx94" - _MACPFX84SFX[""] = "_mpusfxsubret" - _VLDMAXSTRING = 1e+06 - } - function _macpfx84(F, D, C, p1, p2, p3) - { - return _mpusub(_MACPFX84SFX, D, C, D[_mpuptr++], p1, p2, p3) - } - function _macsfx94(F, D, C, p1, p2, p3) - { - return _mpuretsub(D, _handle8494(_mpuacc)) - } - function _movarr(D, S) - { - #_______________________________________________________________________ - ################################################### - delete D - D[""] - delete D[""] - _addarr(D, S) - } - - function _mpu(t, F, p1, p2, p3, D, C) - { - if (patsplit(t, C, /[\x84\x93\x94]/, D) > 0) { - _conline("CODE") - _conl() - _conl(_dumparr(C)) - _conline("DATA") - _conl() - _conl(_dumparr(D)) - _mpuptr = 0 - _mpucc0 = "" - _mpusub(F, D, C, D[_mpuptr++], p1, p2, p3) - return _mpuacc - } - return t - } - function _mpudefaulthnd(F, D, C, p1, p2, p3) - { - # - # /rexpstr/ -> datastr - # (\x00\t\+)* -> 28 00 09 5B 2B 29 - # - # unesc all non-rexp characters: replace unesc of rexp-characters but do not remove it: \* -> \*, \x2A -> \*, \052 -> \*, \\ -> \# - _mpuretsub(D, _mpucc0) - } - function _mpupfxsubret(F, D, C, p1, p2, p3) - { - return 1 - } - function _mpuretsub(D, t) - { - _mpuacc = D[_mpuptr++] - _accmpu(D, t) - return 1 - } - function _mpusfxsubret(F, D, C, p1, p2, p3) - { - return -1 - } - function _mpusub(F, D, C, d, p1, p2, p3, q) - { - q = D[_ARRLEN] - if (_VLDMAXSTRING < length(d)) { - D[--D[_ARRLEN]] = d - _mpuacc = "" + + + +function _mpudefaulthnd(F, D, C, p1, p2, p3) +{ + _mpuretsub(D, _mpucc0) +} + +function _mpupfxsubret(F, D, C, p1, p2, p3) +{ + return 1 +} + +function _mpuretsub(D, t) +{ + _mpuacc = D[_mpuptr++] + _accmpu(D, t) + return 1 +} + +function _mpusfxsubret(F, D, C, p1, p2, p3) +{ + return -1 +} + +function _mpusub(F, D, C, d, p1, p2, p3, q) +{ + q = D[_ARRLEN] + if (_VLDMAXSTRING < length(d)) { + D[--D[_ARRLEN]] = d + _mpuacc = "" + } else { + _mpuacc = d + } + d = _mpucc0 + _conl("_mpusub enter: in `" _mpuacc "' / _mpuptr=" _mpuptr "'") + do { + if ((_mpucc0 = C[_mpuptr]) in F) { + if (isarray(F[_mpucc0])) { + _mpufn0 = F[_mpucc0] + } + _conl("FN: `" _mpucc0 "' > CALL: `" _mpufn0 "' : _mpuacc=" _mpuacc "'") } else { - _mpuacc = d - } - d = _mpucc0 - _conl("_mpusub enter: in `" _mpuacc "' / _mpuptr=" _mpuptr "'") - do { - if ((_mpucc0 = C[_mpuptr]) in F) { - if (isarray(F[_mpucc0])) { - _mpufn0 = F[_mpucc0] - } - _conl("FN: `" _mpucc0 "' > CALL: `" _mpufn0 "' : _mpuacc=" _mpuacc "'") - } else { - _mpufn0 = "_mpudefaulthnd" + _mpufn0 = "_mpudefaulthnd" + } + } while (! _accmpu(D, _mpuacc, @_mpufn0(F, D, C, p1, p2, p3))) + if (_mpufn0 == -1) { + _conl("WARNING: unclosed expression: `" d _mpuacc "'") + _mpuacc = d _mpuacc + } + _retarrm(D, q, "", (_mpufn0 == -1 ? _th0(d, _mpusubwrng("WARNING: unclosed expression", d _mpuacc)) : "")) + # collect: _mpuacc=_retarr(D) _mpuacc + _conl("mpusub exit: _mpuacc: `" _mpuacc "'") +} + +#_______________________________________________________________________ +function _n(F, v, p) +{ + ##################################################### + for (p in _UIDSDEL) { + delete _UIDSDEL[p] + delete _ptr[p] + delete _tPREV[p] + delete _tPARENT[p] + delete _tNEXT[p] + delete _tFCHLD[p] + delete _tQCHLD[p] + delete _tLCHLD[p] + delete _TMP0[p] + delete _TMP1[p] + delete _tLINK[p] + delete _tCLASS[p] + return _nN_i0(p, F, v) + } + for (p in _UIDS) { + delete _UIDS[p] + return _nN_i0(p, F, v) + } + return _nN_i0(_tgenuid(), F, v) +} + +#_____________________________________________________ +function _nN_i0(p, F, v) +{ + _[p][""] + delete _[p][""] + _ptr[p][""] + delete _ptr[p][""] + _TMP0[p][_ARRLEN] = _TMP1[p][_ARRLEN] = 0 + if (isarray(F)) { + delete F[p] + if (isarray(v)) { + F[p][""] + delete F[p][""] + _copyarr(F[p], v) + } else { + if (! (v == 0 && v == "")) { + F[p] = v } - } while (! _accmpu(D, _mpuacc, @_mpufn0(F, D, C, p1, p2, p3))) - if (_mpufn0 == -1) { - _conl("WARNING: unclosed expression: `" d _mpuacc "'") - _mpuacc = d _mpuacc - } - # collect: _mpuacc=_retarr(D) _mpuacc - _retarrm(D, q, "", (_mpufn0 == -1 ? _th0(d, _mpusubwrng("WARNING: unclosed expression", d _mpuacc)) : "")) - _conl("mpusub exit: _mpuacc: `" _mpuacc "'") - } - - function _n(F, v, p) - { - for (p in _UIDSDEL) { - #_______________________________________________________________________ - ##################################################### - delete _UIDSDEL[p] - delete _ptr[p] - delete _tPREV[p] - delete _tPARENT[p] - delete _tNEXT[p] - delete _tFCHLD[p] - delete _tQCHLD[p] - delete _tLCHLD[p] - delete _TMP0[p] - delete _TMP1[p] - delete _tLINK[p] - delete _tCLASS[p] - return _nN_i0(p, F, v) } - for (p in _UIDS) { - delete _UIDS[p] - return _nN_i0(p, F, v) - } - return _nN_i0(_tgenuid(), F, v) - } - - function _nN_i0(p, F, v) - { - #_____________________________________________________ - _[p][""] - delete _[p][""] - _ptr[p][""] - delete _ptr[p][""] - _TMP0[p][_ARRLEN] = _TMP1[p][_ARRLEN] = 0 - if (isarray(F)) { - delete F[p] + } else { + if (! (F == 0 && F == "")) { if (isarray(v)) { - F[p][""] - delete F[p][""] - _copyarr(F[p], v) + _[p][F][""] + delete _[p][F][""] + _copyarr(_[p][F], v) } else { - if (! (v == 0 && v == "")) { - F[p] = v - } - } - } else { - if (! (F == 0 && F == "")) { - if (isarray(v)) { - _[p][F][""] - delete _[p][F][""] - _copyarr(_[p][F], v) + if (v == 0 && v == "") { + _mpu(F, p) } else { - if (v == 0 && v == "") { - _mpu(F, p) - } else { - _[p][F] = v - } + _[p][F] = v } } } - return p } + return p +} - function _newclrdir(f) - { - #_________________________________________________________________ - ############################################ - if ((f = _filerd(f)) == "") { - return - } - _cmd("rd " f " /S /Q 2>NUL") +#_________________________________________________________________ +function _newclrdir(f) +{ + ############################################ + if ((f = _filerd(f)) == "") { + return + } + _cmd("rd " f " /S /Q 2>NUL") + _cmd("md " f " 2>NUL") + _WFILEROOTDIR[f] + return f +} + +#_______________________________________________________________________ +function _newdir(f) +{ + ##################################################### + if ((f = _filerd(f)) == "") { + return + } + if (! (f in _WFILEROOTDIR)) { _cmd("md " f " 2>NUL") _WFILEROOTDIR[f] - return f } - - function _newdir(f) - { - #_______________________________________________________________________ - ##################################################### - if ((f = _filerd(f)) == "") { + return f +} + +############################## +#_______________________________________________________________________ +function _nop(p0, p1, p2, p3) +{ +} + +#_____________________________________________________ +# _retarr(ARRAY,start,prefixtr,postfixtr) +# Return string collected from elements of ARRAY. +# The data elements in ARRAY have numeric indexes. By default it starts from element with index 1, but it is possible to locate elements starting from +# 0,-1,-.... The last data element in the ARRAY have the highest numeric index that is stored in ARRAY[_ARRLEN]. +# Optimized for very large data size. +# +# IN: ARRAY - source data array(is ARRAY is not array then return undefined) +# start - (optional) start index in ARRAY; if missed or have non-numeric value then start array index will be 1. +# prefixst - the string that will be inserted in the begin of generated return string +# postfix - the string that will be added at the end of generated return string +# MOD: - +# OUT: - +# RETURN: undefined - if ARRAY is not array; if ARRAY is empty; if start is higher than ARRAY last element index +# string - collected string: prefixtr-arraydata-postfixtr +#_________________________________________________________________ +function _nretarr(A, i, v, r, q) +{ + ##################################### + if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { + if (i <= (r = q - 16)) { + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + while (i < r) { + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + } + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) return } - if (! (f in _WFILEROOTDIR)) { - _cmd("md " f " 2>NUL") - _WFILEROOTDIR[f] - } - return f + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + return } - - function _nop(p0, p1, p2, p3) - { - } - - function _nretarr(A, i, v, r, q) - { - if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { - if (i <= (r = q - 16)) { - #_____________________________________________________ - # _retarr(ARRAY,start,prefixtr,postfixtr) - # Return string collected from elements of ARRAY. - # The data elements in ARRAY have numeric indexes. By default it starts from element with index 1, but it is possible to locate elements starting from - # 0,-1,-.... The last data element in the ARRAY have the highest numeric index that is stored in ARRAY[_ARRLEN]. - # Optimized for very large data size. - # - # IN: ARRAY - source data array(is ARRAY is not array then return undefined) - # start - (optional) start index in ARRAY; if missed or have non-numeric value then start array index will be 1. - # prefixst - the string that will be inserted in the begin of generated return string - # postfix - the string that will be added at the end of generated return string - # MOD: - - # OUT: - - # RETURN: undefined - if ARRAY is not array; if ARRAY is empty; if start is higher than ARRAY last element index - # string - collected string: prefixtr-arraydata-postfixtr - #_________________________________________________________________ - ##################################### - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - while (i < r) { - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - } - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) - return - } + _ARRSTR = v + return +} + +#___________________________________________________________ +function _nretarrd(A, i, v, r, q) +{ + ############################## + if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { + if (i <= (r = q - 16)) { + _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + while (i < r) { + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + } + _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + } else { _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) - return } + } else { _ARRSTR = v - return } - - function _nretarrd(A, i, v, r, q) - { - if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) { - if (i <= (r = q - 16)) { - #___________________________________________________________ - ############################## - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] - while (i < r) { - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] + delete A + A[""] + delete A[""] +} + +#___________________________________________________________________________________ +#################################################################################### + +#___________________________________________________________________________________ +function _out(t, a, b) +{ + ############################################################### + a = BINMODE + b = ORS + BINMODE = "rw" + ORS = "" + print(t) > _SYS_STDOUT + fflush(_SYS_STDOUT) + BINMODE = a + ORS = b + return t +} + +#_________________________________________________________________ +function _outnl(t) +{ + ################################################ + return _out(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) +} + +function _p1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s1, p1, p2, p3, p4, p5, p6, p7) +} + +function _p2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s2, p1, p2, p3, p4, p5, p6, p7) +} + +function _p3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s3, p1, p2, p3, p4, p5, p6, p7) +} + +function _p4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s4, p1, p2, p3, p4, p5, p6, p7) +} + +function _p5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s5, p1, p2, p3, p4, p5, p6, p7) +} + +function _p6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s6, p1, p2, p3, p4, p5, p6, p7) +} + +function _p7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s7, p1, p2, p3, p4, p5, p6, p7) +} + +function _p8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + _qparamf0 = "_p" _QMAP[_qparamc1--] + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s8, p1, p2, p3, p4, p5, p6, p7) +} + +#_______________________________________________________________________ +function _pass(A, f, t, p2, i, a) +{ + ########################################### + a = _endpass_v0 + _endpass_v0 = "" + i = 1 + while (t && i) { + i = "" + while ((i = A[i]) && t == (t = @i(f, t, p2))) { + } + } + if (i && _endpass_v0) { + A["!"] = 1 + t = _endpass_v0 + } else { + delete A["!"] + } + _endpass_v0 = a + return t +} + +# this is somnitelno: that / / . / / com 56 / / - is the DEV...; what is DEV ??? this already PROBLEM +#_____________________________________________________________________________ +function _patharr0(D, q, i, h, A, B) +{ + ############################################## + delete D + if (0 < (q = split(gensub(/\\/, "/", "G", gensub(/ *([:$\\\/]) */, "\\1", "G", gensub(/(^[ \t]+)|([ \t]+$)/, "", "G", q))), A, /\/+/, B))) { + if (2 > (h = length(B[1]))) { + D["type"] = "FILE" + A[1] = _patharr0_i0(A[1], D, "drive") + return _patharr0_i1(D, A, 1, q) + } + i = gensub(/ *([\.\?]) */, "\\1", "G", A[2]) + IGNORECASE = 1 + match(A[1], /^((https?)|(ftp)):$/) + IGNORECASE = 0 + if (RLENGTH > 0) { + D["type"] = toupper(substr(A[1], 1, RLENGTH - 1)) + _patharr0_i0(i, D, "site", "port") + } else { + if (A[1] == "") { + D["type"] = "UNC" + if (h > 2) { + D["host"] + A[2] = _patharr0_i0(A[2], D, "drive", "", "FILE") + return _patharr0_i1(D, A, 2, q) + } + if (i == "") { + return 1 } - _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + D["host"] = i + A[3] = _patharr0_i0(A[3], D, "drive", "", "FILE") } else { - _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i) + D["type"] = "FILE" + A[1] = _patharr0_i0(A[1], D, "drive") + return _patharr0_i1(D, A, 1, q) } - } else { - _ARRSTR = v } - delete A - A[""] - delete A[""] + return _patharr0_i1(D, A, 3, q) } +} - function _out(t, a, b) - { - #___________________________________________________________________________________ - #################################################################################### - #___________________________________________________________________________________ - ############################################################### - a = BINMODE - b = ORS - BINMODE = "rw" - ORS = "" - print(t) > _SYS_STDOUT - fflush(_SYS_STDOUT) - BINMODE = a - ORS = b +#_____________________________________________________ +function _patharr0_i0(t, D, l, r, d, i) +{ + if (i = index(t, ":")) { + if (d) { + D["type"] = d + } + if (i > 1) { + D[l] = substr(t, 1, i - 1) + } + if ((t = substr(t, i + 1)) && r) { + D[r] = t + } return t + } else { + if (t && r) { + D[l] = t + } } + return t +} - function _outnl(t) - { - #_________________________________________________________________ - ################################################ - return _out(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"]))) - } - - function _p1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s1, p1, p2, p3, p4, p5, p6, p7) - } - - function _p2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s2, p1, p2, p3, p4, p5, p6, p7) +#_____________________________________________________ +function _patharr0_i1(D, A, i, q, t, c) +{ + if (D["type"] == "UNC") { + if (t = A[i++]) { + D[0] = (D["share"] = D[++c] = t) "/" + } else { + return 1 + } } - - function _p3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s3, p1, p2, p3, p4, p5, p6, p7) + while (i < q) { + D[0] = D[0] (D[++c] = A[i++]) "/" } - - function _p4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s4, p1, p2, p3, p4, p5, p6, p7) + if (i == q) { + if (match(t = A[i], /\.[^\.]*$/)) { + if (RSTART > 1) { + D["name"] = substr(t, 1, RSTART - 1) + } + D["ext"] = substr(t, RSTART, RLENGTH) + } else { + if (t != "") { + D["name"] = t + } + } } + return 1 +} - function _p5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s5, p1, p2, p3, p4, p5, p6, p7) - } +############################################################################# - function _p6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s6, p1, p2, p3, p4, p5, p6, p7) - } - function _p7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s7, p1, p2, p3, p4, p5, p6, p7) - } - function _p8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { +function _pmap(m, s1, s2, s3, s4, s5, s6, s7, s8) +{ + if (match(m, /^([^\(]+)\(([^\)]*)\)$/, _QMAP)) { + _qparamf1 = _QMAP[1] + _QMAP[0] = "r" (_qparamc1 = split(_QMAP[2], _QMAP, "")) _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8, s8, p1, p2, p3, p4, p5, p6, p7) - } - - function _pass(A, f, t, p2, i, a) - { - #_______________________________________________________________________ - ########################################### - a = _endpass_v0 - _endpass_v0 = "" - i = 1 - while (t && i) { - i = "" - while ((i = A[i]) && t == (t = @i(f, t, p2))) { + return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8) + } +} + +function _pr0(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1() +} + +function _pr1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1) +} + +function _pr2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2) +} + +function _pr3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3) +} + +function _pr4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4) +} + +function _pr5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5) +} + +function _pr6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6) +} + +function _pr7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6, p7) +} + +function _pr8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) +{ + return @_qparamf1(p1, p2, p3, p4, p5, p6, p7, p8) +} + +#_________________________________________________________________ +function _printarr(A, t, lv, r, a) +{ + #################################### + a = PROCINFO["sorted_in"] + PROCINFO["sorted_in"] = "_lengthsort" + _printarrexp = (r ? r : "") + if (isarray(A)) { + delete _DUMPARR + _dumparrc = _dumparrd = "" + _printarr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) + PROCINFO["sorted_in"] = a + return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") + } +} + +#___________________________________________________________ +function _printarr_i1(A, lv, ls, ln, t, t2, i, a, f) +{ + t2 = _getchrln(" ", length(t)) + if (ln == lv) { + if (ls > 0) { + for (i in A) { + ++a } - } - if (i && _endpass_v0) { - A["!"] = 1 - t = _endpass_v0 } else { - delete A["!"] + for (i in A) { + (isarray(A[i]) ? ++a : "") + } } - _endpass_v0 = a - return t + if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" + } + return } - - function _patharr0(D, q, i, h, A, B) - { - # this is somnitelno: that / / . / / com 56 / / - is the DEV...; what is DEV ??? this already PROBLEM - #_____________________________________________________________________________ - ############################################## - delete D - if (0 < (q = split(gensub(/\\/, "/", "G", gensub(/ *([:$\\\/]) */, "\\1", "G", gensub(/(^[ \t]+)|([ \t]+$)/, "", "G", q))), A, /\/+/, B))) { - if (2 > (h = length(B[1]))) { - D["type"] = "FILE" - A[1] = _patharr0_i0(A[1], D, "drive") - return _patharr0_i1(D, A, 1, q) - } - i = gensub(/ *([\.\?]) */, "\\1", "G", A[2]) - IGNORECASE = 1 - match(A[1], /^((https?)|(ftp)):$/) - IGNORECASE = 0 - if (RLENGTH > 0) { - D["type"] = toupper(substr(A[1], 1, RLENGTH - 1)) - _patharr0_i0(i, D, "site", "port") - } else { - if (A[1] == "") { - D["type"] = "UNC" - if (h > 2) { - D["host"] - A[2] = _patharr0_i0(A[2], D, "drive", "", "FILE") - return _patharr0_i1(D, A, 2, q) - } - if (i == "") { - return 1 + if (ls >= 0) { + for (i in A) { + if (! _printarrexp || i ~ _printarrexp) { + if (! isarray(A[i])) { + if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" } - D["host"] = i - A[3] = _patharr0_i0(A[3], D, "drive", "", "FILE") - } else { - D["type"] = "FILE" - A[1] = _patharr0_i0(A[1], D, "drive") - return _patharr0_i1(D, A, 1, q) } } - return _patharr0_i1(D, A, 3, q) } } - - function _patharr0_i0(t, D, l, r, d, i) - { - if (i = index(t, ":")) { - #_____________________________________________________ - if (d) { - D["type"] = d - } - if (i > 1) { - D[l] = substr(t, 1, i - 1) - } - if ((t = substr(t, i + 1)) && r) { - D[r] = t - } - return t - } else { - if (t && r) { - D[l] = t + for (i in A) { + if (isarray(A[i])) { + if (! _printarrexp || i ~ _printarrexp) { + _printarr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") } } - return t } - - function _patharr0_i1(D, A, i, q, t, c) - { - if (D["type"] == "UNC") { - #_____________________________________________________ - if (t = A[i++]) { - D[0] = (D["share"] = D[++c] = t) "/" - } else { - return 1 - } + if (! f) { + if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { + _conl(_dumparrd) + _dumparrd = "" } - while (i < q) { - D[0] = D[0] (D[++c] = A[i++]) "/" - } - if (i == q) { - if (match(t = A[i], /\.[^\.]*$/)) { - if (RSTART > 1) { - D["name"] = substr(t, 1, RSTART - 1) - } - D["ext"] = substr(t, RSTART, RLENGTH) + } +} + +function _qparam(qm, p0, p1, p2, p3, p4, p5, p6, p7) +{ + if (qm == qm + 0 && qm > 0) { + _qparamim = substr(" ", 1, qm) + } else { + if (qm != "") { + _qparamim = qm + } else { + _qparamim = " " + } + } + _qparamask = "" + return _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) +} + +function _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) +{ + _qparama0 = substr(_qparamim, 1, 1) + _qparamim = substr(_qparamim, 2) + switch (_qparama0) { + case "": + gsub(/ +$/, "", _qparamask) + return length(_qparamask) + default: + if (isarray(p0)) { + _qparama0 = "A" + } else { + if (p0 == "" && p0 == 0) { + _qparama0 = " " } else { - if (t != "") { - D["name"] = t + if (_isptr(p0)) { + _qparama0 = "P" + } else { + _qparama0 = "S" } } } - return 1 + case ".": + _qparamask = _qparamask _qparama0 + return _qparam_i0(p1, p2, p3, p4, p5, p6, p7) + } +} + +#_______________________________________________________________________ +function _qstr(t, c, A, B) +{ + ################################################ + c = "" + for (t = split(t, A, /[\x00-\x1F\\"]/, B); t >= 0; t--) { + c = _QSTR[B[t]] A[t + 1] c + } + return c +} + +#_________________________________________________________________ +function _qstrq(t) +{ + ################################################ + gsub(/\\/, "\\\\", t) + gsub(/"/, "\\\"", t) + return t +} + +################################################################ +#_____________________________________________________________________________ +function _rEG(c, t, P, a, A) +{ + ##################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return _ln("_reg 0.001") + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _pmap(m, s1, s2, s3, s4, s5, s6, s7, s8) - { - if (match(m, /^([^\(]+)\(([^\)]*)\)$/, _QMAP)) { - ############################################################################# - _qparamf1 = _QMAP[1] - _QMAP[0] = "r" (_qparamc1 = split(_QMAP[2], _QMAP, "")) - _qparamf0 = "_p" _QMAP[_qparamc1--] - return @_qparamf0(s1, s2, s3, s4, s5, s6, s7, s8) +#_______________________________________________________________________ +function _rFBRO(p) +{ + ###################################################### + if (p) { + if (p in _tPARENT) { + return _tFCHLD[_tPARENT[p]] } + while (p in _tPREV) { + p = _tPREV[p] + } + return p } - - function _pr0(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1() - } - - function _pr1(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1) - } - - function _pr2(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2) + return p +} + +#_______________________________________________________________________ +function _rFCHLD(p) +{ + ##################################################### + if (p && p in _tFCHLD) { + return _tFCHLD[p] + } + return "" +} + +######################## p="", !v +#_______________________________________________________________________ +function _rLBRO(p) +{ + ###################################################### + if (p) { + if (p in _tPARENT) { + return _tLCHLD[_tPARENT[p]] + } + while (p in _tNEXT) { + p = _tNEXT[p] + } + return p } - - function _pr3(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3) + return p +} + +######################## p="" +#_______________________________________________________________________ +function _rLCHLD(p) +{ + ##################################################### + if (p && p in _tLCHLD) { + return _tLCHLD[p] + } + return "" +} + +#_______________________________________________________________________ +function _rLINK(p) +{ + ###################################################### + return ((p in _tLINK ? _tLINK[p] : "")) +} + +######################## p="" +#_______________________________________________________________________ +function _rNEXT(p) +{ + ###################################################### + if (p && p in _tNEXT) { + return _tNEXT[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rPARENT(p) +{ + #################################################### + if (p && p in _tPARENT) { + return _tPARENT[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rPREV(p) +{ + ###################################################### + if (p && p in _tPREV) { + return _tPREV[p] + } + return "" +} + +######################## p="" +#_______________________________________________________________________ +function _rQBRO(p, c, p1) +{ + ################################################ + if (p) { + if (p in _tPARENT) { + return _tQCHLD[_tPARENT[p]] + } + c = 1 + p1 = p + while (p1 in _tPREV) { + c++ + p1 = _tPREV[p1] + } + while (p in _tNEXT) { + c++ + p = _tNEXT[p] + } + return c } - - function _pr4(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4) + return p +} + +######################## p="" +#_______________________________________________________________________ +function _rQCHLD(p) +{ + ##################################################### + if (p && p in _tQCHLD) { + return _tQCHLD[p] + } + return "" +} + +#___________________________________________________________________________________ +# EMMULATED FUNCTIONAL FIELDS ###################################################### + +#_____________________________________________________________________________ +function _rSQFIRST(g, p, A) +{ + ##################################################### + if (isarray(A)) { + return _rSQFIRSTA(g, p, A) + } + _SQTOPTR[g] = p + _SQSTACK[g][0] = 0 + return _rsqgetptr(g, p) +} + +#_________________________________________________________________ +function _rSQFIRSTA(g, p, A) +{ + ######################################## + _SQTOPTR[g] = p + _SQSTACK[g][0] = 0 + if ((p = _rsqgetptr(g, p)) in A) { + return p } + return _rSQNEXTA(g, p, A) +} - function _pr5(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5) +#_______________________________________________________________________ +function _rSQNEXT(g, p, A) +{ + ################################################ + if (isarray(A)) { + return _rSQNEXTA(g, p, A) } + return _rsqnext_i0(g, p) +} - function _pr6(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6) +#_________________________________________________________________ +function _rSQNEXTA(g, p, A) +{ + ######################################### + if (p == _SQTOPTR[g]) { + if (_SQSTACK[g][0] > 0) { + _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] + return _rSQNEXTA(g, _SQSTACK[g][_SQSTACK[g][0]--], A) + } + return } - - function _pr7(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6, p7) + while (p in _tNEXT) { + if ((p = _rsqgetptr(g, _tNEXT[p])) in A) { + return p + } } + return ((p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], A) : "")) +} - function _pr8(s1, s2, s3, s4, s5, s6, s7, s8, p1, p2, p3, p4, p5, p6, p7, p8) - { - return @_qparamf1(p1, p2, p3, p4, p5, p6, p7, p8) - } +function _rconl(t) +{ + _rprt = _rprt _ln(t) +} - function _printarr(A, t, lv, r, a) - { - #_________________________________________________________________ - #################################### - a = PROCINFO["sorted_in"] - PROCINFO["sorted_in"] = "_lengthsort" - _printarrexp = (r ? r : "") - if (isarray(A)) { - delete _DUMPARR - _dumparrc = _dumparrd = "" - _printarr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t)) - PROCINFO["sorted_in"] = a - return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "") - } - } +function _rconline(t) +{ + _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1)) +} - function _printarr_i1(A, lv, ls, ln, t, t2, i, a, f) - { - #___________________________________________________________ - t2 = _getchrln(" ", length(t)) - if (ln == lv) { - if (ls > 0) { - for (i in A) { - ++a - } - } else { - for (i in A) { - (isarray(A[i]) ? ++a : "") - } - } - if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - return - } - if (ls >= 0) { - for (i in A) { - if (! _printarrexp || i ~ _printarrexp) { - if (! isarray(A[i])) { - if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - } - } - } - } - for (i in A) { - if (isarray(A[i])) { - if (! _printarrexp || i ~ _printarrexp) { - _printarr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]") +#___________________________________________________________ +function _rd_shortcut(D, f) +{ + if ((_shrtcutf0 = _filepath(f)) && _shortcut_nerr(_shrtcuta0 = _cmd(_shortcut_fpath " /A:Q /F:\"" _shrtcutf0 "\" 2>&1"), _shrtcutf0)) { + ERRNO = "" + split(_shrtcuta0, _SHRTCUTA0, /\x0D?\x0A/) + for (_shrtcuta0 in _SHRTCUTA0) { + for (f in _SHORTCUTRSTRUC) { + if (match(_SHRTCUTA0[_shrtcuta0], "^" f)) { + D[_SHORTCUTRSTRUC[f]] = substr(_SHRTCUTA0[_shrtcuta0], 1 + RLENGTH) } } } - if (! f) { - if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) { - _conl(_dumparrd) - _dumparrd = "" - } - } } + return ((ERRNO ? ERRNO = "read shortcut: " ERRNO : _NOP)) +} - function _qparam(qm, p0, p1, p2, p3, p4, p5, p6, p7) - { - if (qm == qm + 0 && qm > 0) { - _qparamim = substr(" ", 1, qm) - } else { - if (qm != "") { - _qparamim = qm +#_______________________________________________________________________ +function _rdfile(f, i, A) +{ + ################################################ + if ((f = _filerdne(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return + } + _fio_cmda = RS + RS = ".{1,}" + _fio_cmdb = BINMODE + BINMODE = "rw" + ERRNO = RT = _NUL + getline RS < f + BINMODE = _fio_cmdb + RS = _fio_cmda + if (ERRNO == "") { + close(f) + } + if (ERRNO == "") { + return RT + } + return (RT = _NOP) +} + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# fn _th0,_th1,_th2,_th3 +# USAGE: +# _th0(p1,p2,p3,p4) +# +# Each of this functions can have up to 4 parameters. +# _th0(p1,p2,p3,p4) return 1st parameter (p1) +# _th1(p1,p2,p3,p4) return 2nd parameter (p2) +# _th2(p1,p2,p3,p4) return 3rd parameter (p3) +# _th3(p1,p2,p3,p4) return 4th parameter (p4) +#_____________________________________________________________________________ +# fn _nop(p1,p2,p3,p4,p5,p6,p7,p8) +# USAGE: +# _nop() +# +# Does not do any action. No result returned. Up to 8 parameters. +#_____________________________________________________________________________ +# fn _exit(c) +# USAGE: +# _exit(code) +# +# This function do the same as GAWK-operator `exit code'. +#_____________________________________________________________________________ +# fn _getdate() +# fn _getime() +# fn _getsecond() +# fn _getsecondsync() +function _rdreg(D, p) +{ + ################################################################ + _rdregp0 = "reg query \"" p "\" /S /reg:64 2>NUL" + _rdregfld = _rdregkey = 0 + _rdregq0 = split(gensub(/[\x0D?\x0A]{2,}/, _CHR["EOL"], "G", _cmd(_rdregp0)), _RDREGA0, /\x0D?\x0A/) + while (_rdregq0 > 0) { + _rdreg_i0(D) + } + return (_rdregfld + _rdregkey) +} + +#___________________________________________________________ +function _rdreg_i0(D, A) +{ + while (_rdregq0 > 0) { + if (match(_rdregp0 = _RDREGA0[_rdregq0--], / (.*) REG_((SZ)|(DWORD)|(QWORD)|(BINARY)|(EXPAND_SZ)|(MULTI_SZ)) (.*)$/, A)) { + if (! _rdreg_i0(D)) { + ++_rdregfld + D[_rdregp0 A[1] "." _RDREGTYPE[A[2]]] = A[9] + return } else { - _qparamim = " " + break } - } - _qparamask = "" - return _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) - } - - function _qparam_i0(p0, p1, p2, p3, p4, p5, p6, p7) - { - _qparama0 = substr(_qparamim, 1, 1) - _qparamim = substr(_qparamim, 2) - switch (_qparama0) { - case "": - gsub(/ +$/, "", _qparamask) - return length(_qparamask) - default: - if (isarray(p0)) { - _qparama0 = "A" - } else { - if (p0 == "" && p0 == 0) { - _qparama0 = " " - } else { - if (_isptr(p0)) { - _qparama0 = "P" - } else { - _qparama0 = "S" - } - } + } else { + if (_rdregp0 ~ /^HK/) { + ++_rdregkey + return D[_rdregp0 = _rdregp0 "\\"] } - case ".": - _qparamask = _qparamask _qparama0 - return _qparam_i0(p1, p2, p3, p4, p5, p6, p7) } } + return 1 +} - function _qstr(t, c, A, B) - { - #_______________________________________________________________________ - ################################################ - c = "" - for (t = split(t, A, /[\x00-\x1F\\"]/, B); t >= 0; t--) { - c = _QSTR[B[t]] A[t + 1] c - } - return c - } +#_____________________________________________________________________________________________________ +###################################################################################################### - function _qstrq(t) - { - #_________________________________________________________________ - ################################################ - gsub(/\\/, "\\\\", t) - gsub(/"/, "\\\"", t) - return t - } - function _rEG(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - ################################################################ - #_____________________________________________________________________________ - ##################################################### - #___________________________________________________________ - #_____________________________________________________ - return t - case "_lib_APPLY": - #_____________________________________________________ - return - case "_lib_HELP": - #_____________________________________________________ - return - case "_lib_NAMEVER": - #_____________________________________________________ - return _ln("_reg 0.001") - case "_lib_BEGIN": - #_____________________________________________________ - return - case "_lib_END": - return - } - } - function _rFBRO(p) - { - if (p) { - if (p in _tPARENT) { - #_______________________________________________________________________ - ###################################################### - return _tFCHLD[_tPARENT[p]] - } - while (p in _tPREV) { - p = _tPREV[p] - } - return p - } - return p - } - function _rFCHLD(p) - { - if (p && p in _tFCHLD) { - #_______________________________________________________________________ - ##################################################### - return _tFCHLD[p] - } - return "" - } - function _rLBRO(p) - { - if (p) { - if (p in _tPARENT) { - ######################## p="", !v - #_______________________________________________________________________ - ###################################################### - return _tLCHLD[_tPARENT[p]] - } - while (p in _tNEXT) { - p = _tNEXT[p] - } - return p - } - return p - } - function _rLCHLD(p) - { - if (p && p in _tLCHLD) { - ######################## p="" - #_______________________________________________________________________ - ##################################################### - return _tLCHLD[p] - } - return "" - } - function _rLINK(p) - { - #_______________________________________________________________________ - ###################################################### - return ((p in _tLINK ? _tLINK[p] : "")) - } - function _rNEXT(p) - { - if (p && p in _tNEXT) { - ######################## p="" - #_______________________________________________________________________ - ###################################################### - return _tNEXT[p] - } - return "" - } - function _rPARENT(p) - { - if (p && p in _tPARENT) { - ######################## p="" - #_______________________________________________________________________ - #################################################### - return _tPARENT[p] - } - return "" - } - function _rPREV(p) - { - if (p && p in _tPREV) { - ######################## p="" - #_______________________________________________________________________ - ###################################################### - return _tPREV[p] - } - return "" - } - function _rQBRO(p, c, p1) - { - if (p) { - if (p in _tPARENT) { - ######################## p="" - #_______________________________________________________________________ - ################################################ - return _tQCHLD[_tPARENT[p]] - } - c = 1 - p1 = p - while (p1 in _tPREV) { - c++ - p1 = _tPREV[p1] - } - while (p in _tNEXT) { - c++ - p = _tNEXT[p] - } - return c - } - return p - } - function _rQCHLD(p) - { - if (p && p in _tQCHLD) { - ######################## p="" - #_______________________________________________________________________ - ##################################################### - return _tQCHLD[p] - } - return "" - } - function _rSQFIRST(g, p, A) - { - #___________________________________________________________________________________ - # EMMULATED FUNCTIONAL FIELDS ###################################################### - #_____________________________________________________________________________ - ##################################################### - if (isarray(A)) { - return _rSQFIRSTA(g, p, A) - } - _SQTOPTR[g] = p - _SQSTACK[g][0] = 0 - return _rsqgetptr(g, p) - } - function _rSQFIRSTA(g, p, A) - { - #_________________________________________________________________ - ######################################## - _SQTOPTR[g] = p - _SQSTACK[g][0] = 0 - if ((p = _rsqgetptr(g, p)) in A) { - return p - } - return _rSQNEXTA(g, p, A) - } - function _rSQNEXT(g, p, A) - { - #_______________________________________________________________________ - ################################################ - if (isarray(A)) { - return _rSQNEXTA(g, p, A) - } - return _rsqnext_i0(g, p) - } - function _rSQNEXTA(g, p, A) - { - if (p == _SQTOPTR[g]) { - if (_SQSTACK[g][0] > 0) { - #_________________________________________________________________ - ######################################### - _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] - return _rSQNEXTA(g, _SQSTACK[g][_SQSTACK[g][0]--], A) - } - return - } - while (p in _tNEXT) { - if ((p = _rsqgetptr(g, _tNEXT[p])) in A) { - return p - } - } - return ((p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], A) : "")) - } - function _rconl(t) - { - _rprt = _rprt _ln(t) - } - function _rconline(t) - { - _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1)) - } - function _rd_shortcut(D, f) - { - if ((_shrtcutf0 = _filepath(f)) && _shortcut_nerr(_shrtcuta0 = _cmd(_shortcut_fpath " /A:Q /F:\"" _shrtcutf0 "\" 2>&1"), _shrtcutf0)) { - #___________________________________________________________ - ERRNO = "" - split(_shrtcuta0, _SHRTCUTA0, /\x0D?\x0A/) - for (_shrtcuta0 in _SHRTCUTA0) { - for (f in _SHORTCUTRSTRUC) { - if (match(_SHRTCUTA0[_shrtcuta0], "^" f)) { - D[_SHORTCUTRSTRUC[f]] = substr(_SHRTCUTA0[_shrtcuta0], 1 + RLENGTH) - } - } - } - } - return ((ERRNO ? ERRNO = "read shortcut: " ERRNO : _NOP)) - } - function _rdfile(f, i, A) - { - if ((f = _filerdne(f)) == "" || _filene(f) == "") { - #_______________________________________________________________________ - ################################################ - ERRNO = "Filename error" - return - } - _fio_cmda = RS - RS = ".{1,}" - _fio_cmdb = BINMODE - BINMODE = "rw" - ERRNO = RT = _NUL - getline RS < f - BINMODE = _fio_cmdb - RS = _fio_cmda - if (ERRNO == "") { - close(f) - } - if (ERRNO == "") { - return RT - } - return (RT = _NOP) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +function _rdsafe(A, i, d) +{ + if (i in A) { + return A[i] } + return d +} - function _rdreg(D, p) - { - #################################################################################### - # PUBLIC: - #_____________________________________________________________________________ - # fn _th0,_th1,_th2,_th3 - # USAGE: - # _th0(p1,p2,p3,p4) - # - # Each of this functions can have up to 4 parameters. - # _th0(p1,p2,p3,p4) return 1st parameter (p1) - # _th1(p1,p2,p3,p4) return 2nd parameter (p2) - # _th2(p1,p2,p3,p4) return 3rd parameter (p3) - # _th3(p1,p2,p3,p4) return 4th parameter (p4) - #_____________________________________________________________________________ - # fn _nop(p1,p2,p3,p4,p5,p6,p7,p8) - # USAGE: - # _nop() - # - # Does not do any action. No result returned. Up to 8 parameters. - #_____________________________________________________________________________ - # fn _exit(c) - # USAGE: - # _exit(code) - # - # This function do the same as GAWK-operator `exit code'. - #_____________________________________________________________________________ - # fn _getdate() - # fn _getime() - # fn _getsecond() - # fn _getsecondsync() - ################################################################ - _rdregp0 = "reg query \"" p "\" /S /reg:64 2>NUL" - _rdregfld = _rdregkey = 0 - _rdregq0 = split(gensub(/[\x0D?\x0A]{2,}/, _CHR["EOL"], "G", _cmd(_rdregp0)), _RDREGA0, /\x0D?\x0A/) - while (_rdregq0 > 0) { - _rdreg_i0(D) - } - return (_rdregfld + _rdregkey) - } - - function _rdreg_i0(D, A) - { - while (_rdregq0 > 0) { - if (match(_rdregp0 = _RDREGA0[_rdregq0--], / (.*) REG_((SZ)|(DWORD)|(QWORD)|(BINARY)|(EXPAND_SZ)|(MULTI_SZ)) (.*)$/, A)) { - if (! _rdreg_i0(D)) { - #___________________________________________________________ - ++_rdregfld - D[_rdregp0 A[1] "." _RDREGTYPE[A[2]]] = A[9] - return +#_______________________________________________________________________ +function _reg_check(p) +{ + _tframe("_reg_check_i0", p, p) +} + +#_______________________________________________ +function _reg_check_i0(p, pp, p1, p2) +{ + if (_[p]["TYPE"] == "defreg") { + if (_[p]["REGPATH"] in _REG) { + if ("VALUE" in _[p]) { + if (_[p]["VALUE"] == _REG[_[p]["REGPATH"]]) { + _creport(p, substr("OK: REGENTRY MATCH(==" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) } else { - break + _dllerr(p, substr("REGENTRY NOT MATCH(!=" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) } } else { - if (_rdregp0 ~ /^HK/) { - ++_rdregkey - return D[_rdregp0 = _rdregp0 "\\"] + if (_VAR[_[p]["REGPATH"]] == _REG[_[p]["REGPATH"]]) { + _creport(p, substr("OK: REGPATH MATCH(==" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + } else { + _dllerr(p, substr("REGPATH NOT MATCH(!=" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) } } + } else { + _dllerr(p, substr("REGPATH NOT FOUND: " _[p]["REGPATH"], 1, 126)) } - return 1 - } - - function _rdsafe(A, i, d) - { - #_____________________________________________________________________________________________________ - ###################################################################################################### - if (i in A) { - return A[i] - } - return d } +} - function _reg_check(p) - { - #_______________________________________________________________________ - _tframe("_reg_check_i0", p, p) - } +#_____________________________________________________ +function _registryinit() +{ + _registrytmpfile = _getmpfile() +} - function _reg_check_i0(p, pp, p1, p2) - { - if (_[p]["TYPE"] == "defreg") { - if (_[p]["REGPATH"] in _REG) { - if ("VALUE" in _[p]) { - #_______________________________________________ - if (_[p]["VALUE"] == _REG[_[p]["REGPATH"]]) { - _creport(p, substr("OK: REGENTRY MATCH(==" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) - } else { - _dllerr(p, substr("REGENTRY NOT MATCH(!=" _[p]["VALUE"] "): " _[p]["REGPATH"], 1, 126)) - } +# _rdregfld : gvar - number of readed registry fields by _rdreg() +# _rdregkey : gvar - number of readed registry keys by _rdreg() +#_____________________________________________________________________________ +function _regpath0(D, i, s, q, S) +{ + ############################################ 0 # + if (i = _patharr0(S, i)) { + if ("name" in S) { + D["name"] = S["name"] + } + if ("ext" in S) { + D["ext"] = S["ext"] + } + s = ((toupper(s = (i in S ? S[i] : "")) in _REGPATH0REGDIR ? D[++q] = _REGPATH0REGDIR[toupper(s)] : (D[++q] = _REGPATH0REGDIR[""]) "\\" (D[++q] = s))) "\\" + while (++i in S) { + s = s (D[++q] = S[i]) "\\" + } + if (s != "") { + D[0] = s + } + IGNORECASE = 1 + D["hostdir"] = "\\\\" (D["host"] = ("host" in S && ("" == (i = S["host"]) || "." == i || "?" == i || "localhost" == i) ? ENVIRON["COMPUTERNAME"] : i)) "\\" s + IGNORECASE = 0 + } +} + +#_________________________________________________________________________________________ +function _report(p) +{ + ####################################################################### + _report_t0 = _reportparnt = "" + _report_i0(p) + _tframe("_report_i0", p) + return _report_t0 +} + +function _report_i0(p, p0, p1, p2) +{ + if (p in _tPARENT) { + if (_reportparnt != (_reportparnt = _tPARENT[p])) { + _report_t0 = _report_t0 _ln() _ln((z = "_ " _[_tPARENT[p]]["NAME"] " ") _getchrln("_", _CON_WIDTH - length(z) - 2)) _ln(_getchrln("#", _CON_WIDTH - 2)) _ln() + } + } + if ("ERROR" in _[p]) { + _report_t0 = _report_t0 _reporterr(p, _[p]["ERROR"]) + } + if ("REPORT" in _[p]) { + _report_t0 = _report_t0 _ln(_[p]["REPORT"]) + } +} + +#___________________________________________________________________________________ +function _reporterr(p, t3, pp, t, t2) +{ + t = "" + pp = p + do { + ("NAME" in _[pp] ? t = _[pp]["NAME"] ": " t : "") + } while (pp = _rPARENT(pp)) + if (match(t3, /\x00/)) { + return (substr(t3, 1, RSTART - 1) t substr(t3, RSTART + 1)) + } + return (t t3) +} + +#___________________________________________________________________________________ +#################################################################################### + + + + +#_______________________________________________________________________ +# _CHR array +# +# _CHR[ASC-code decimal number]=="char" +# +# Contains 256 elements. The index is the decimal number from 0-255. +# The value is the single character with ASC-code equivalent to index number: +# +# _CHR[97] =="a" - character with ASC-code 97 is `a' +# +# This array is useful if you want to get character using it's ASC-code +#_________________________________________________________________ +# _ASC array +# +# _ASC[char]==number: ASC-code of char +# +# Contains 256 elements. The index is the any single character with ASC-code \x00-\xFF. +# The value is the number equivalent of character's ASC-code: +# +# _ASC["A"] ==65 - ASC-code of character `A' is 65 +# +# This array is useful if you want to get ASC-code of the character. +#_________________________________________________________________ +# _QASC array +# +# _QASC[char]=="string: octal ASC-code of char in 3-digit octal format" +# +# Contains 256 elements. The index is the any single charcter with ASC-code \x00-\xFF. +# The value is the octal number equivalent of character's ASC-code in fixed-length - 3-digit - string: +# +# _QASC["!"] =="041" - ASC-code of character `!' is 33(decimal) == 41(in octal) +# _QASC["\x0D"] =="015" +# +# This array is useful when some type of string escape conversion is performed. It allows quickly get +# replace string for the characters that can be specified only by character code in result string: +# +# "\x0D" -> "\\015" +#_______________________________________________________________________ + + + + + + + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# fn _getchrln(ptt,len) +#_____________________________________________________________________________ +# fn _tabtospc(src,tabstep,xcoord) +#################################################################################### + +#_____________________________________________________________________________ +function _retarr(A, i, p, a, q) +{ + ################################################## + if (isarray(A)) { + i = (i == "" ? 0 : i + 0) + q = A[_ARRLEN] + 0 + if (i < q) { + return (p A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + } + } +} + +function _retarr_i0(A, q, i, a) +{ + if (i < q) { + return (A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + } + while (q < i) { + delete A[++q] + } + return a +} + +#_________________________________________________________________ +function _retarrd(A, v, i) +{ + ######################################### + if (1 in A) { + return (A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12] A[13] A[14] A[15] A[16] (((i = 17) in A ? _retarrd_i0(A, i) v : v))) + } + delete A + return v +} + +#_____________________________________________________ +function _retarrd_i0(A, i) +{ + if (i in A) { + return (A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] ((i in A ? _retarrd_i0(A, i) : ""))) + } + delete A +} + +#_______________________________________________________________________ +######################################################################## +#EXPERIMENTAL + +function _rexpfn(R, t, p) +{ + _REXPFN[""] = "" + while (t) { + t = _rxpfn(R, t, p) + } + return _REXPFN[""] +} + +function _rexpfnend(t) +{ + _REXPFN[""] = t +} + +#_____________________________________________________________________________ +function _rexpstr(r, i, c, A) +{ + ################################################### + c = split(r, A, "") + r = "" + for (i = 1; i <= c; i++) { + r = r _REXPSTR[A[i]] + } + return r +} + +#_____________________________________________________________________________ +function _rexpstr_i0(t, A, p0) +{ + return (_REXPSTR[t] = "\\" t) +} + +#___________________________________________________________ +function _rmtsharerr(h, t) +{ + gsub(/[\x0D\x0A]+/, "", t) + if (t ~ /^The command failed: 53/) { + ERRNO = "host not found: \\\\" h + } else { + ERRNO = t ": \\\\" h + } +} + +function _rpp(q, D, S) +{ + _conl() + _conline(q) + _conl() + _regpath0(D, q) + #_conl(_dumparr(D)) + + _conl(_ln("DEST:") _dumparr(D)) + _conl() + return q +} + +#_________________________________________________________________________________________ +function _rrdreg(DD, p, k, t, v, c, i, q, tT, A, B, C, D) +{ + ############################################# old; regedit + if (! _registrytmpfile) { + _registryinit() + } + _cmd("regedit /E \"" _registrytmpfile "\" \"" p "\" 2>&1") + q = patsplit(gensub(/[\x00\xFF\xFE]+/, "", "G", _rdfile(_registrytmpfile)), A, /\x0D?\x0A\[[^\]]+\]\x0D?\x0A/, B) + for (i = 1; i <= q; i++) { + p = gensub(/(^[ \t\x0D\x0A]*\[)|((\\)\\+)|(\][ \t\x0D\x0A]*$)/, "\\3", "G", A[i]) + DD[p "\\"] + delete C[split(B[i], C, /[\x0D\x0A]+/)] + for (c = 1; c in C; c++) { + tt = tt C[c] + if (gsub(/\\$/, "", tt)) { + continue + } + if (tt == "") { + continue + } + if (match(_th0(tt, tt = ""), /((^"(([^\\"]|\\.)*)")|(@))=(("(([^\\"]|\\.)*)")|(dword:([[:xdigit:]]{8}))|(hex(\(([27b])\))?:(.*)))$/, D)) { + if (D[7]) { + t = "STR" + v = _unstr(D[8]) } else { - if (_VAR[_[p]["REGPATH"]] == _REG[_[p]["REGPATH"]]) { - _creport(p, substr("OK: REGPATH MATCH(==" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + if (D[10]) { + t = "W32" + v = D[11] } else { - _dllerr(p, substr("REGPATH NOT MATCH(!=" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126)) + v = D[15] + if (D[13]) { + switch (D[14]) { + case "2": + t = "XSZ" + break + case "7": + t = "MSZ" + break + default: + t = "W64" + } + } else { + t = "BIN" + } } } + DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] ((D[5] ? "(Default)" : ""))) "." t)] = v } else { - _dllerr(p, substr("REGPATH NOT FOUND: " _[p]["REGPATH"], 1, 126)) + _fatal("regedit: unknown output format(" c "): `" C[c] "'") } } } +} - function _registryinit() - { - #_____________________________________________________ - _registrytmpfile = _getmpfile() - } - - function _regpath0(D, i, s, q, S) - { - if (i = _patharr0(S, i)) { - # _rdregfld : gvar - number of readed registry fields by _rdreg() - # _rdregkey : gvar - number of readed registry keys by _rdreg() - #_____________________________________________________________________________ - ############################################ 0 # - if ("name" in S) { - D["name"] = S["name"] - } - if ("ext" in S) { - D["ext"] = S["ext"] - } - s = ((toupper(s = (i in S ? S[i] : "")) in _REGPATH0REGDIR ? D[++q] = _REGPATH0REGDIR[toupper(s)] : (D[++q] = _REGPATH0REGDIR[""]) "\\" (D[++q] = s))) "\\" - while (++i in S) { - s = s (D[++q] = S[i]) "\\" - } - if (s != "") { - D[0] = s - } - IGNORECASE = 1 - D["hostdir"] = "\\\\" (D["host"] = ("host" in S && ("" == (i = S["host"]) || "." == i || "?" == i || "localhost" == i) ? ENVIRON["COMPUTERNAME"] : i)) "\\" s - IGNORECASE = 0 +#_________________________________________________________________ +function _rsqgetptr(g, p, A) +{ + if (p in _tLINK) { + _SQSTACK[g][++_SQSTACK[g][0]] = p + _SQSTACK[g][++_SQSTACK[g][0]] = _SQTOPTR[g] + while ((p = _tLINK[p]) in _tLINK) { + _con(".") } + _SQTOPTR[g] = p } - - function _report(p) - { - #_________________________________________________________________________________________ - ####################################################################### - _report_t0 = _reportparnt = "" - _report_i0(p) - _tframe("_report_i0", p) - return _report_t0 + if (p in _tFCHLD) { + return _rsqgetptr(g, _tFCHLD[p]) } + return p +} - function _report_i0(p, p0, p1, p2) - { - if (p in _tPARENT) { - if (_reportparnt != (_reportparnt = _tPARENT[p])) { - _report_t0 = _report_t0 _ln() _ln((z = "_ " _[_tPARENT[p]]["NAME"] " ") _getchrln("_", _CON_WIDTH - length(z) - 2)) _ln(_getchrln("#", _CON_WIDTH - 2)) _ln() - } - } - if ("ERROR" in _[p]) { - _report_t0 = _report_t0 _reporterr(p, _[p]["ERROR"]) - } - if ("REPORT" in _[p]) { - _report_t0 = _report_t0 _ln(_[p]["REPORT"]) +#___________________________________________________________ +function _rsqnext_i0(g, p) +{ + if (p == _SQTOPTR[g]) { + if (_SQSTACK[g][0] > 0) { + _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] + return _rsqnext_i0(g, _SQSTACK[g][_SQSTACK[g][0]--]) } + return } - - function _reporterr(p, t3, pp, t, t2) - { - #___________________________________________________________________________________ - t = "" - pp = p - do { - ("NAME" in _[pp] ? t = _[pp]["NAME"] ": " t : "") - } while (pp = _rPARENT(pp)) - if (match(t3, /\x00/)) { - return (substr(t3, 1, RSTART - 1) t substr(t3, RSTART + 1)) - } - return (t t3) - } - - function _retarr(A, i, p, a, q) - { - if (isarray(A)) { - #___________________________________________________________________________________ - #################################################################################### - #_______________________________________________________________________ - # _CHR array - # - # _CHR[ASC-code decimal number]=="char" - # - # Contains 256 elements. The index is the decimal number from 0-255. - # The value is the single character with ASC-code equivalent to index number: - # - # _CHR[97] =="a" - character with ASC-code 97 is `a' - # - # This array is useful if you want to get character using it's ASC-code - #_________________________________________________________________ - # _ASC array - # - # _ASC[char]==number: ASC-code of char - # - # Contains 256 elements. The index is the any single character with ASC-code \x00-\xFF. - # The value is the number equivalent of character's ASC-code: - # - # _ASC["A"] ==65 - ASC-code of character `A' is 65 - # - # This array is useful if you want to get ASC-code of the character. - #_________________________________________________________________ - # _QASC array - # - # _QASC[char]=="string: octal ASC-code of char in 3-digit octal format" - # - # Contains 256 elements. The index is the any single charcter with ASC-code \x00-\xFF. - # The value is the octal number equivalent of character's ASC-code in fixed-length - 3-digit - string: - # - # _QASC["!"] =="041" - ASC-code of character `!' is 33(decimal) == 41(in octal) - # _QASC["\x0D"] =="015" - # - # This array is useful when some type of string escape conversion is performed. It allows quickly get - # replace string for the characters that can be specified only by character code in result string: - # - # "\x0D" -> "\\015" - #_______________________________________________________________________ - #################################################################################### - # PUBLIC: - #_____________________________________________________________________________ - # fn _getchrln(ptt,len) - #_____________________________________________________________________________ - # fn _tabtospc(src,tabstep,xcoord) - #################################################################################### - #_____________________________________________________________________________ - ################################################## - i = (i == "" ? 0 : i + 0) - q = A[_ARRLEN] + 0 - if (i < q) { - return (p A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) + if (p in _tNEXT) { + return _rsqgetptr(g, _tNEXT[p]) + } + return _rsqnext_i0(g, _tPARENT[p]) +} + +function _rtn(v, A) +{ + _conl() + _conline(_val(v) " : " _val(A)) + _conl() + _rtn2(v, A) + _conl() +} + +function _rtn2(v, A, r, t) +{ + r = (isarray(A) ? _typa(v, A) : _typ(v)) + if ("`" > _t0 && _t0) { + _conl("ggggg") + } + t = ((r ? "TRUE" : "FALSE")) " / " ((r > 0 ? r ">0" : r "!>0")) " / " ((r + 0 > 0 ? r "+0>0" : r "+0!>0")) " / " ((r + 0 != r ? r "+0!=" r : r "+0==" r)) " / " ((r && "`" > r ? "'`'>" r " && " r : "!('`'>" r " && " r ")")) + _conl("`" r "' : " t) + return r +} + +function _rxpfn(R, t, p, i, f, A) +{ + for (i in R) { + if (match(t, i, A)) { + f = R[i] + if (t != (t = @f(A, substr(t, RLENGTH + 1), p))) { + return t } } } + return _rexpfnend(t) +} - function _retarr_i0(A, q, i, a) - { - if (i < q) { - return (A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] _retarr_i0(A, q, i, a)) - } - while (q < i) { - delete A[++q] - } - return a - } - - function _retarrd(A, v, i) - { - #_________________________________________________________________ - ######################################### - if (1 in A) { - return (A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12] A[13] A[14] A[15] A[16] (((i = 17) in A ? _retarrd_i0(A, i) v : v))) - } - delete A - return v +############################################################## +#_____________________________________________________________________________ +function _sHARE(c, t, P, a, A) +{ + ################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #_____________________________________________________ + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return _ln("_share 1.000") + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _retarrd_i0(A, i) - { +################################################################ +#_____________________________________________________________________________ +function _sYS(c, t, P, a, A) +{ + ##################################################### + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t #_____________________________________________________ - if (i in A) { - return (A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] A[i++] ((i in A ? _retarrd_i0(A, i) : ""))) - } - delete A + case "_lib_APPLY": + return + #_____________________________________________________ + case "_lib_HELP": + return + #_____________________________________________________ + case "_lib_NAMEVER": + return + #_____________________________________________________ + case "_lib_BEGIN": + return + #_____________________________________________________ + case "_lib_END": + return } +} - function _rexpfn(R, t, p) - { - #_______________________________________________________________________ - ######################################################################## - #EXPERIMENTAL - _REXPFN[""] = "" - while (t) { - t = _rxpfn(R, t, p) +#_______________________________________________________________________ +function _serv_check(p) +{ + _tframe("_serv_check_i0", p, p) +} + +#_______________________________________________ +function _serv_check_i0(p, p0, p1, p2, p3, i, q, c) +{ + if (_[p]["TYPE"] == "defsrv") { + i = IGNORECASE + IGNORECASE = 1 + if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) { + _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112)) + } else { + _dllerr(p, "service " _[p]["SERVNAME"] " not detected") } - return _REXPFN[""] } + IGNORECASE = i +} - function _rexpfnend(t) - { - _REXPFN[""] = t +#_______________________________________________________________________ +function _setarrsort(f, a) +{ + ############################################## + a = PROCINFO["sorted_in"] + if (! f) { + delete PROCINFO["sorted_in"] + } else { + PROCINFO["sorted_in"] = f } + return a +} - function _rexpstr(r, i, c, A) - { - #_____________________________________________________________________________ - ################################################### - c = split(r, A, "") - r = "" - for (i = 1; i <= c; i++) { - r = r _REXPSTR[A[i]] +#_______________________________________________________________________ +function _setmpath(p, a) +{ + ################################################ + ERRNO = "" + if (p && (a = _filerd(p))) { + if (_FILEIO_TMPRD) { + _FILEIO_TMPATHS[_FILEIO_TMPRD] } - return r + #if ( _filexist(a) ) _del(a) + #_cmd("rd " a " /S /Q 2>NUL"); _cmd("del " a " /Q 2>NUL") + return (_FILEIO_TMPRD = a) + } else { + return _warning("`" p "': cannot set temporary folder" ((ERRNO ? ": " ERRNO : ""))) } +} - function _rexpstr_i0(t, A, p0) - { - #_____________________________________________________________________________ - return (_REXPSTR[t] = "\\" t) - } +#_________________________________________________________________________________________ +########################################################################################## - function _rmtsharerr(h, t) - { - #___________________________________________________________ - gsub(/[\x0D\x0A]+/, "", t) - if (t ~ /^The command failed: 53/) { - ERRNO = "host not found: \\\\" h - } else { - ERRNO = t ": \\\\" h - } - } - function _rpp(q, D, S) - { - _conl() - _conline(q) - _conl() - #_conl(_dumparr(D)) - _regpath0(D, q) - _conl(_ln("DEST:") _dumparr(D)) - _conl() - return q - } - function _rrdreg(DD, p, k, t, v, c, i, q, tT, A, B, C, D) - { - #_________________________________________________________________________________________ - ############################################# old; regedit - if (! _registrytmpfile) { - _registryinit() - } - _cmd("regedit /E \"" _registrytmpfile "\" \"" p "\" 2>&1") - q = patsplit(gensub(/[\x00\xFF\xFE]+/, "", "G", _rdfile(_registrytmpfile)), A, /\x0D?\x0A\[[^\]]+\]\x0D?\x0A/, B) - for (i = 1; i <= q; i++) { - p = gensub(/(^[ \t\x0D\x0A]*\[)|((\\)\\+)|(\][ \t\x0D\x0A]*$)/, "\\3", "G", A[i]) - DD[p "\\"] - delete C[split(B[i], C, /[\x0D\x0A]+/)] - for (c = 1; c in C; c++) { - tt = tt C[c] - if (gsub(/\\$/, "", tt)) { - continue - } - if (tt == "") { - continue - } - if (match(_th0(tt, tt = ""), /((^"(([^\\"]|\\.)*)")|(@))=(("(([^\\"]|\\.)*)")|(dword:([[:xdigit:]]{8}))|(hex(\(([27b])\))?:(.*)))$/, D)) { - if (D[7]) { - t = "STR" - v = _unstr(D[8]) - } else { - if (D[10]) { - t = "W32" - v = D[11] - } else { - v = D[15] - if (D[13]) { - switch (D[14]) { - case "2": - t = "XSZ" - break - case "7": - t = "MSZ" - break - default: - t = "W64" - } - } else { - t = "BIN" - } - } - } - DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] ((D[5] ? "(Default)" : ""))) "." t)] = v - } else { - _fatal("regedit: unknown output format(" c "): `" C[c] "'") - } - } - } - } - function _rsqgetptr(g, p, A) - { - if (p in _tLINK) { - #_________________________________________________________________ - _SQSTACK[g][++_SQSTACK[g][0]] = p - _SQSTACK[g][++_SQSTACK[g][0]] = _SQTOPTR[g] - while ((p = _tLINK[p]) in _tLINK) { - _con(".") - } - _SQTOPTR[g] = p - } - if (p in _tFCHLD) { - return _rsqgetptr(g, _tFCHLD[p]) - } - return p - } - function _rsqnext_i0(g, p) - { - if (p == _SQTOPTR[g]) { - if (_SQSTACK[g][0] > 0) { - #___________________________________________________________ - _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--] - return _rsqnext_i0(g, _SQSTACK[g][_SQSTACK[g][0]--]) - } - return - } - if (p in _tNEXT) { - return _rsqgetptr(g, _tNEXT[p]) - } - return _rsqnext_i0(g, _tPARENT[p]) - } - function _rtn(v, A) - { - _conl() - _conline(_val(v) " : " _val(A)) - _conl() - _rtn2(v, A) - _conl() - } - function _rtn2(v, A, r, t) - { - r = (isarray(A) ? _typa(v, A) : _typ(v)) - if ("`" > _t0 && _t0) { - _conl("ggggg") - } - t = ((r ? "TRUE" : "FALSE")) " / " ((r > 0 ? r ">0" : r "!>0")) " / " ((r + 0 > 0 ? r "+0>0" : r "+0!>0")) " / " ((r + 0 != r ? r "+0!=" r : r "+0==" r)) " / " ((r && "`" > r ? "'`'>" r " && " r : "!('`'>" r " && " r ")")) - _conl("`" r "' : " t) - return r - } - function _rxpfn(R, t, p, i, f, A) - { - for (i in R) { - if (match(t, i, A)) { - f = R[i] - if (t != (t = @f(A, substr(t, RLENGTH + 1), p))) { - return t - } - } - } - return _rexpfnend(t) - } - function _sHARE(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - ############################################################## - #_____________________________________________________________________________ - ################################################### - #___________________________________________________________ - #_____________________________________________________ - return t - case "_lib_APPLY": - #_____________________________________________________ - return - case "_lib_HELP": - #_____________________________________________________ - return - case "_lib_NAMEVER": - #_____________________________________________________ - return _ln("_share 1.000") - case "_lib_BEGIN": - #_____________________________________________________ - return - case "_lib_END": - return - } - } - function _sYS(c, t, P, a, A) - { - switch (c) { - case "_lib_CMDLN": - ################################################################ - #_____________________________________________________________________________ - ##################################################### - #___________________________________________________________ - #_____________________________________________________ - return t - case "_lib_APPLY": - #_____________________________________________________ - return - case "_lib_HELP": - #_____________________________________________________ - return - case "_lib_NAMEVER": - #_____________________________________________________ - return - case "_lib_BEGIN": - #_____________________________________________________ - return - case "_lib_END": - return - } - } - function _serv_check(p) - { - #_______________________________________________________________________ - _tframe("_serv_check_i0", p, p) - } - function _serv_check_i0(p, p0, p1, p2, p3, i, q, c) - { - if (_[p]["TYPE"] == "defsrv") { - #_______________________________________________ - i = IGNORECASE - IGNORECASE = 1 - if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) { - _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112)) - } else { - _dllerr(p, "service " _[p]["SERVNAME"] " not detected") - } - } - IGNORECASE = i - } - function _setarrsort(f, a) - { - #_______________________________________________________________________ - ############################################## - a = PROCINFO["sorted_in"] - if (! f) { - delete PROCINFO["sorted_in"] - } else { - PROCINFO["sorted_in"] = f - } - return a - } - function _setmpath(p, a) - { - #_______________________________________________________________________ - ################################################ - ERRNO = "" - if (p && (a = _filerd(p))) { - #if ( _filexist(a) ) _del(a) - #_cmd("rd " a " /S /Q 2>NUL"); _cmd("del " a " /Q 2>NUL") - if (_FILEIO_TMPRD) { - _FILEIO_TMPATHS[_FILEIO_TMPRD] - } - return (_FILEIO_TMPRD = a) - } else { - return _warning("`" p "': cannot set temporary folder" ((ERRNO ? ": " ERRNO : ""))) - } - } - - function _sharelist(D, h, q, c, l, A, B) - { - #_________________________________________________________________________________________ - ########################################################################################## - ################################################# - delete D - c = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) " 2>&1" - if (match(c = _cmd(c), /\x0AShare[^\x0A]*Remark/)) { - gsub(/(^[^-]*\x0D?\x0A-+\x0D?\x0A[ \t]*)|(\x0D?\x0AThe command completed successfully.*$)/, "", c) - l = RLENGTH - 7 - split(c, A, /([ \t]*\x0D?\x0A)+[ \t]*/) - for (c in A) { - if (match(A[c], /((([^ \t:]+[ \t]+)*[^ \t:]+)[ \t]+)([A-Za-z])[ \t]*:/, B) && ++q) { - D[B[2]] = (A[c] ~ /\.\.\.$/ ? _sharepath(h, B[2]) : gensub(/[ \t\\\/]*$/, "\\\\", 1, substr(A[c], 1 + B[1, "length"], l - B[1, "length"]))) - } + + + + + + +function _sharelist(D, h, q, c, l, A, B) +{ + ################################################# + delete D + c = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) " 2>&1" + if (match(c = _cmd(c), /\x0AShare[^\x0A]*Remark/)) { + gsub(/(^[^-]*\x0D?\x0A-+\x0D?\x0A[ \t]*)|(\x0D?\x0AThe command completed successfully.*$)/, "", c) + l = RLENGTH - 7 + split(c, A, /([ \t]*\x0D?\x0A)+[ \t]*/) + for (c in A) { + if (match(A[c], /((([^ \t:]+[ \t]+)*[^ \t:]+)[ \t]+)([A-Za-z])[ \t]*:/, B) && ++q) { + D[B[2]] = (A[c] ~ /\.\.\.$/ ? _sharepath(h, B[2]) : gensub(/[ \t\\\/]*$/, "\\\\", 1, substr(A[c], 1 + B[1, "length"], l - B[1, "length"]))) } - return q } - return _rmtsharerr(h, c) + return q } + return _rmtsharerr(h, c) +} - function _sharepath(h, s, A) - { - #_____________________________________________________________________________ - ################################################### - s = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) "\\\"" s "\" 2>&1" - if (match(s = _cmd(s), /\x0APath[ \t]+([^\x0D\x0A]+)/, _SHAREPATHA0)) { - return gensub(/[ \t\\\/]*$/, "\\\\", 1, _SHAREPATHA0[1]) - } - return _rmtsharerr(h, s) +#_____________________________________________________________________________ +function _sharepath(h, s, A) +{ + ################################################### + s = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) "\\\"" s "\" 2>&1" + if (match(s = _cmd(s), /\x0APath[ \t]+([^\x0D\x0A]+)/, _SHAREPATHA0)) { + return gensub(/[ \t\\\/]*$/, "\\\\", 1, _SHAREPATHA0[1]) } + return _rmtsharerr(h, s) +} - function _shortcut(D, S) - { - # filepath,filepath2* - [over]write shorcut file filepath; shortcut parameters will be defined from shortcut file filepath2(copy shortcut) - if (isarray(D)) { - # array,ptr* - copy from array _[ptr] to array shorcut-specific elements - if (isarray(S)) { - ############################################################# - _addarrmask(D, S, _SHORTCUTWSTRUC) +function _shortcut(D, S) +{ + ############################################################# + if (isarray(D)) { + if (isarray(S)) { + _addarrmask(D, S, _SHORTCUTWSTRUC) + } else { + if (S == 0 && S == "") { + # array,array2* - copy from array2 to array shorcut-specific elements + _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) } else { - if (S == 0 && S == "") { - # array,array2* - copy from array2 to array shorcut-specific elements - _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) + if (_isnotfileptr(S)) { + # array* - define shortcut-specific elements in array by default values + _addarrmask(D, _[S], _SHORTCUTWSTRUC) } else { - if (_isnotfileptr(S)) { - # array* - define shortcut-specific elements in array by default values - _addarrmask(D, _[S], _SHORTCUTWSTRUC) - } else { - if (_rd_shortcut(D, S)) { - return - } + if (_rd_shortcut(D, S)) { + return } } } + } + # array,ptr* - copy from array _[ptr] to array shorcut-specific elements + } else { + if (D == 0 && D == "") { + return _NOP } else { - if (D == 0 && D == "") { - return _NOP - } else { - if (_isnotfileptr(D)) { - # ptr,ptr2* - copy from array _[ptr2] to array _[ptr] shorcut-specific elements - if (isarray(S)) { - # array,filepath* - define in array shortcut-specific elements by reading its from shortcut file filepath(load shortcut) - # -* - no action(return -) - _addarrmask(_[D], S, _SHORTCUTWSTRUC) + if (_isnotfileptr(D)) { + # -* - no action(return -) + if (isarray(S)) { + _addarrmask(_[D], S, _SHORTCUTWSTRUC) + } else { + if (S == 0 && S == "") { + # ptr,array* - copy from array to array _[ptr] shorcut-specific elements + _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) } else { - if (S == 0 && S == "") { - # ptr,array* - copy from array to array _[ptr] shorcut-specific elements - _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC) + if (_isnotfileptr(S)) { + # ptr* - define shortcut-specifc elements in array _[ptr] by default values + _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) } else { - if (_isnotfileptr(S)) { - # ptr* - define shortcut-specifc elements in array _[ptr] by default values - _addarrmask(_[D], _[S], _SHORTCUTWSTRUC) - } else { - if (_rd_shortcut(_[D], S)) { - return - } + if (_rd_shortcut(_[D], S)) { + return } } } + } + # ptr,ptr2* - copy from array _[ptr2] to array _[ptr] shorcut-specific elements + } else { + # ptr,filepath* - define in array _[ptr] shortcut-specific elements by reading its from shortcut file filepath(load shortcut) + if (isarray(S) && _wr_shortcut(D, S)) { + return } else { - # ptr,filepath* - define in array _[ptr] shortcut-specific elements by reading its from shortcut file filepath(load shortcut) - # filepath,array* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array(save shortcut) - # filepath* - [over]write shorcut file filepath; shortcut parameters will be defined by default values - # filepath,ptr* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array _[ptr](save shortcut) - if (isarray(S) && _wr_shortcut(D, S)) { + if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) { return } else { - if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) { + if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) { return } else { - if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) { + if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) { return - } else { - if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) { - return - } } } } } - } - } - return 1 - } - - function _shortcut_init(A, B, q) - { - #________________________________________________ - _SHORTCUTERR[2] = "file not found" - _SHORTCUTERR[3] = "no such filepath" - _SHORTCUTERR["The system cannot find the file specified."] = "no such filepath" - _SHORTCUTERR[5] = "file is folder" - _SHORTCUTERR["Access is denied."] = "file is folder" - _SHORTCUTERR[123] = "filepath syntax error" - _SHORTCUTERR["The filename, directory name, or volume label syntax is incorrect."] = "filepath syntax error" - q = "target\t\t\t/T:\t\t\t\tTargetPath=\t\t\t\t\ttarget?\t\t\t;\t\t\t_target\t\t\t\t\t\t\tTargetPathExpanded=\t\t\t\t\t\t\t;\t\t\tparameters\t\t\t/P:\t\t\t\tArguments=\t\t\t\t\tparaneters?\t\t\t;\t\t\t_parameters\t\t\t\t\t\t\tArgumentsExpanded=\t\t\t\t\t\t\t;\t\t\tstartdir\t\t\t/W:\t\t\t\tWorkingDirectory=\t\t\t\tstartdir?\t\t\t;\t\t\t_startdir\t\t\t\t\t\t\tWorkingDirectoryExpanded=\t\t\t\t\t\t;\t\t\trunstyle\t\t\t/R:\t\t\t\tRunStyle=\t\t\t\t\t1\t\t\t\t;\t\t\ticon,index\t\t\t/I:\t\t\t\tIconLocation=\t\t\t\ticon,index?\t\t\t;\t\t\txicon,index\t\t\t\t\t\t\tIconLocationExpanded=\t\t\t\t\t\t\t;\t\t\tshortcut key\t\t/H:\t\t\t\tHotKey=\t\t\t\t\t0\t\t\t\t;\t\t\tdescription\t\t\t/D:\t\t\t\tDescription=\t\t\t\t_env4: default shortcut\t" - split(q, _SHRTCUTA0, /[ \t]*;[ \t]*/) - for (q in _SHRTCUTA0) { - if (match(_SHRTCUTA0[q], /^([^\t]+)\t+([^\t]+)(\t+([^\t]+)(\t+([^\t]+))?)?/, B)) { - if (B[3] == "") { - _SHORTCUTRSTRUC[B[2]] = B[1] + # filepath,ptr* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array _[ptr](save shortcut) + } + } + } + # filepath,filepath2* - [over]write shorcut file filepath; shortcut parameters will be defined from shortcut file filepath2(copy shortcut) + return 1 +} + +#________________________________________________ +function _shortcut_init(A, B, q) +{ + _SHORTCUTERR[2] = "file not found" + _SHORTCUTERR[3] = "no such filepath" + _SHORTCUTERR["The system cannot find the file specified."] = "no such filepath" + _SHORTCUTERR[5] = "file is folder" + _SHORTCUTERR["Access is denied."] = "file is folder" + _SHORTCUTERR[123] = "filepath syntax error" + _SHORTCUTERR["The filename, directory name, or volume label syntax is incorrect."] = "filepath syntax error" + q = "target\t\t\t/T:\t\t\t\tTargetPath=\t\t\t\t\ttarget?\t\t\t;\t\t\t_target\t\t\t\t\t\t\tTargetPathExpanded=\t\t\t\t\t\t\t;\t\t\tparameters\t\t\t/P:\t\t\t\tArguments=\t\t\t\t\tparaneters?\t\t\t;\t\t\t_parameters\t\t\t\t\t\t\tArgumentsExpanded=\t\t\t\t\t\t\t;\t\t\tstartdir\t\t\t/W:\t\t\t\tWorkingDirectory=\t\t\t\tstartdir?\t\t\t;\t\t\t_startdir\t\t\t\t\t\t\tWorkingDirectoryExpanded=\t\t\t\t\t\t;\t\t\trunstyle\t\t\t/R:\t\t\t\tRunStyle=\t\t\t\t\t1\t\t\t\t;\t\t\ticon,index\t\t\t/I:\t\t\t\tIconLocation=\t\t\t\ticon,index?\t\t\t;\t\t\txicon,index\t\t\t\t\t\t\tIconLocationExpanded=\t\t\t\t\t\t\t;\t\t\tshortcut key\t\t/H:\t\t\t\tHotKey=\t\t\t\t\t0\t\t\t\t;\t\t\tdescription\t\t\t/D:\t\t\t\tDescription=\t\t\t\t_env4: default shortcut\t" + split(q, _SHRTCUTA0, /[ \t]*;[ \t]*/) + for (q in _SHRTCUTA0) { + if (match(_SHRTCUTA0[q], /^([^\t]+)\t+([^\t]+)(\t+([^\t]+)(\t+([^\t]+))?)?/, B)) { + if (B[3] == "") { + _SHORTCUTRSTRUC[B[2]] = B[1] + } else { + if (B[5] == "") { + _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] + delete _SHORTCUTDEFAULT[B[1]] } else { - if (B[5] == "") { - _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] - delete _SHORTCUTDEFAULT[B[1]] - } else { - _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] - _SHORTCUTDEFAULT[B[1]] = B[6] - } + _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2] + _SHORTCUTDEFAULT[B[1]] = B[6] } - } else { - _fatal("_shortcut.init: _shortcut_struc: syntax error: `" _SHRTCUTA0[q] "'") } - } - _SHRTCUTA1[""] - delete _SHRTCUTA1[""] - _shortcut_fpath = "\\\\localhost\\eGAWK\\LIB\\_shortcut\\_shortcut.exe" - } - - function _shortcut_nerr(t, s, A) - { - if (match(t, /\x0ASystem error (-?[0-9]+)[^\x0D\x0A]*[\x0D\x0A]+([^\x0D\x0A]+)/, A)) { - #_____________________________________________________ - ERRNO = ((A[1] in _SHORTCUTERR ? _SHORTCUTERR[A[1]] : (A[2] in _SHORTCUTERR ? _SHORTCUTERR[A[2]] : tolower(gensub(/^(The )?(((.*)\.$)|(.*[^\.]$))/, "\\4\\5", "G", A[2])) "(" A[1] ")"))) ((s ? ": `" s "'" : "")) } else { - return 1 + _fatal("_shortcut.init: _shortcut_struc: syntax error: `" _SHRTCUTA0[q] "'") } } + _SHRTCUTA1[""] + delete _SHRTCUTA1[""] + _shortcut_fpath = "\\\\localhost\\eGAWK\\LIB\\_shortcut\\_shortcut.exe" +} - function _split_regpath() - { - _rpp(" / / / / ") - _rpp(" / / / / huj ") - _rpp(" / / / / huj / ") - _rpp(" / / / / huj / pizda.TSR ") - _rpp(" / / / / hklm ") - _rpp(" / / / / hklm / ") - _rpp(" / / / / hklm / huj ") - _rpp(" / / / / hklm / huj / ") - _rpp(" / / / / hklm / huj / \tpizda.TSR ") - _conl() - _conl("########################################################################################") - _conl() - _rpp(" / / / / hklm / software / altiris / fi le . ex t ") - _rpp(" / / . / / hkcr / software / altiris / fi le . ex t ") - _rpp(" / / ? / / hKcU / software / altiris / fi le . ex t ") - _rpp(" / / lOcAlHoSt / / hKu / software / altiris / fi le . ex t ") - _rpp(" / / ho st / / hKcc / software / altiris / fi le . ex t ") - _rpp(" / / ho st / / hKPd / software / altiris / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - } - - function _splitpath_test() - { - _conl() - _conl("########################################################################################") - _conl() - _fpp(" ") - _fpp(" fi le . ex t ") - _fpp(" di r0 / / ") - _fpp(" di r0 / / fi le . ex t ") - _fpp(" / ") - _fpp(" / fi le . ex t ") - _fpp(" / di r0 / / ") - _fpp(" / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" c : ") - _fpp(" c : fi le . ex t ") - _fpp(" c : di r0 / / ") - _fpp(" c : di r0 / / fi le . ex t ") - _fpp(" c : / / ") - _fpp(" c : / / fi le . ex t ") - _fpp(" c : / / di r0 / / ") - _fpp(" c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / ") - _fpp(" / / ho st . hs t ") - _fpp(" / / ho st / / ") - _fpp(" / / ho st / / fi le . ex t ") - _fpp(" / / ho st / / di r0 / / ") - _fpp(" / / ho st / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / ho st / / c : ") - _fpp(" / / ho st / / c : fi le . ex t ") - _fpp(" / / ho st / / c : di r0 / / ") - _fpp(" / / ho st / / c : di r0 / / fi le . ex t ") - _fpp(" / / ho st / / c : / / ") - _fpp(" / / ho st / / c : / / fi le . ex t ") - _fpp(" / / ho st / / c : / / di r0 / / ") - _fpp(" / / ho st / / c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" http : / / / ") - _fpp(" http : / / / si te . ex t ") - _fpp(" http : / / / si te / / ") - _fpp(" http : / / / si te / / fi le . ex t ") - _fpp(" http : / / / si te / / di r0 / / ") - _fpp(" http : / / / si te / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" ftp : / / / : po rt ") - _fpp(" ftp : / / / si te . ex t : po rt ") - _fpp(" ftp : / / / si te : po rt / / ") - _fpp(" ftp : / / / si te : po rt / / fi le . ex t ") - _fpp(" ftp : / / / si te : po rt / / di r0 / / ") - _fpp(" ftp : / / / si te : po rt / / di r0 / / fi le . ex t ") - _conl() - _conl("## //. ######################################################################################") - _conl() - _fpp(" / / . ") - _fpp(" / / . / / ") - _fpp(" / / . / / com 56 ") - _fpp(" / / . / / com 56 / / ") - _fpp(" / / . / / c : ") - _fpp(" / / . / / c : / / ") - _fpp(" / / . / / c : com 56 ") - _fpp(" / / . / / c : com 56 / / ") - _fpp(" / / . / / c : / / com 56 ") - _fpp(" / / . / / c : / / com 56 / / ") - _conl() - _conl("## //? ######################################################################################") - _conl() - _fpp(" / / ? ") - _fpp(" / / ? / / ") - _fpp(" / / ? / / com 56 ") - _fpp(" / / ? / / com 56 / / ") - _fpp(" / / ? / / c : ") - _fpp(" / / ? / / c : / / ") - _fpp(" / / ? / / c : com 56 ") - _fpp(" / / ? / / c : com 56 / / ") - _fpp(" / / ? / / c : / / com 56 ") - _fpp(" / / ? / / c : / / com 56 / / ") - _conl() - _conl("########################################################################################") - _conl() - _fpp(" / / / ") - _fpp(" / / / . hs t ") - _fpp(" / / / / fi le . ex t ") - _fpp(" / / / / di r0 / / ") - _fpp(" / / / / di r0 / / di r1 / fi le . ex t ") - _fpp(" / / / / c : ") - _fpp(" / / / / c : fi le . ex t ") - _fpp(" / / / / c : di r0 / / ") - _fpp(" / / / / c : di r0 / / fi le . ex t ") - _fpp(" / / / / c : / / ") - _fpp(" / / / / c : / / fi le . ex t ") - _fpp(" / / / / c : / / di r0 / / ") - _fpp(" / / / / c : / / di r0 / / fi le . ex t ") - _conl() - _conl("########################################################################################") - _conl() - return +#_____________________________________________________ +function _shortcut_nerr(t, s, A) +{ + if (match(t, /\x0ASystem error (-?[0-9]+)[^\x0D\x0A]*[\x0D\x0A]+([^\x0D\x0A]+)/, A)) { + ERRNO = ((A[1] in _SHORTCUTERR ? _SHORTCUTERR[A[1]] : (A[2] in _SHORTCUTERR ? _SHORTCUTERR[A[2]] : tolower(gensub(/^(The )?(((.*)\.$)|(.*[^\.]$))/, "\\4\\5", "G", A[2])) "(" A[1] ")"))) ((s ? ": `" s "'" : "")) + } else { + return 1 } - - function _splitstr(A, t, r) - { - if (_istr(t)) { - #_______________________________________________________________________ - ########################################### 1 # - if (_splitstr_i0(A, t) > 0) { - return _splitstrp0 - } - if (_istr(r)) { - return _splitstr_i0(A, r) - } - } else { - if (it == "A") { - if (length(t) > 0) { - _movarr(A, t) - return (0 - length(A)) - } - } - _istr(r) - } +} + +function _split_regpath() +{ + _rpp(" / / / / ") + _rpp(" / / / / huj ") + _rpp(" / / / / huj / ") + _rpp(" / / / / huj / pizda.TSR ") + _rpp(" / / / / hklm ") + _rpp(" / / / / hklm / ") + _rpp(" / / / / hklm / huj ") + _rpp(" / / / / hklm / huj / ") + _rpp(" / / / / hklm / huj / \tpizda.TSR ") + _conl() + _conl("########################################################################################") + _conl() + _rpp(" / / / / hklm / software / altiris / fi le . ex t ") + _rpp(" / / . / / hkcr / software / altiris / fi le . ex t ") + _rpp(" / / ? / / hKcU / software / altiris / fi le . ex t ") + _rpp(" / / lOcAlHoSt / / hKu / software / altiris / fi le . ex t ") + _rpp(" / / ho st / / hKcc / software / altiris / fi le . ex t ") + _rpp(" / / ho st / / hKPd / software / altiris / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() +} + +function _splitpath_test() +{ + _conl() + _conl("########################################################################################") + _conl() + _fpp(" ") + _fpp(" fi le . ex t ") + _fpp(" di r0 / / ") + _fpp(" di r0 / / fi le . ex t ") + _fpp(" / ") + _fpp(" / fi le . ex t ") + _fpp(" / di r0 / / ") + _fpp(" / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" c : ") + _fpp(" c : fi le . ex t ") + _fpp(" c : di r0 / / ") + _fpp(" c : di r0 / / fi le . ex t ") + _fpp(" c : / / ") + _fpp(" c : / / fi le . ex t ") + _fpp(" c : / / di r0 / / ") + _fpp(" c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / ") + _fpp(" / / ho st . hs t ") + _fpp(" / / ho st / / ") + _fpp(" / / ho st / / fi le . ex t ") + _fpp(" / / ho st / / di r0 / / ") + _fpp(" / / ho st / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / ho st / / c : ") + _fpp(" / / ho st / / c : fi le . ex t ") + _fpp(" / / ho st / / c : di r0 / / ") + _fpp(" / / ho st / / c : di r0 / / fi le . ex t ") + _fpp(" / / ho st / / c : / / ") + _fpp(" / / ho st / / c : / / fi le . ex t ") + _fpp(" / / ho st / / c : / / di r0 / / ") + _fpp(" / / ho st / / c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" http : / / / ") + _fpp(" http : / / / si te . ex t ") + _fpp(" http : / / / si te / / ") + _fpp(" http : / / / si te / / fi le . ex t ") + _fpp(" http : / / / si te / / di r0 / / ") + _fpp(" http : / / / si te / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" ftp : / / / : po rt ") + _fpp(" ftp : / / / si te . ex t : po rt ") + _fpp(" ftp : / / / si te : po rt / / ") + _fpp(" ftp : / / / si te : po rt / / fi le . ex t ") + _fpp(" ftp : / / / si te : po rt / / di r0 / / ") + _fpp(" ftp : / / / si te : po rt / / di r0 / / fi le . ex t ") + _conl() + _conl("## //. ######################################################################################") + _conl() + _fpp(" / / . ") + _fpp(" / / . / / ") + _fpp(" / / . / / com 56 ") + _fpp(" / / . / / com 56 / / ") + _fpp(" / / . / / c : ") + _fpp(" / / . / / c : / / ") + _fpp(" / / . / / c : com 56 ") + _fpp(" / / . / / c : com 56 / / ") + _fpp(" / / . / / c : / / com 56 ") + _fpp(" / / . / / c : / / com 56 / / ") + _conl() + _conl("## //? ######################################################################################") + _conl() + _fpp(" / / ? ") + _fpp(" / / ? / / ") + _fpp(" / / ? / / com 56 ") + _fpp(" / / ? / / com 56 / / ") + _fpp(" / / ? / / c : ") + _fpp(" / / ? / / c : / / ") + _fpp(" / / ? / / c : com 56 ") + _fpp(" / / ? / / c : com 56 / / ") + _fpp(" / / ? / / c : / / com 56 ") + _fpp(" / / ? / / c : / / com 56 / / ") + _conl() + _conl("########################################################################################") + _conl() + _fpp(" / / / ") + _fpp(" / / / . hs t ") + _fpp(" / / / / fi le . ex t ") + _fpp(" / / / / di r0 / / ") + _fpp(" / / / / di r0 / / di r1 / fi le . ex t ") + _fpp(" / / / / c : ") + _fpp(" / / / / c : fi le . ex t ") + _fpp(" / / / / c : di r0 / / ") + _fpp(" / / / / c : di r0 / / fi le . ex t ") + _fpp(" / / / / c : / / ") + _fpp(" / / / / c : / / fi le . ex t ") + _fpp(" / / / / c : / / di r0 / / ") + _fpp(" / / / / c : / / di r0 / / fi le . ex t ") + _conl() + _conl("########################################################################################") + _conl() + return +} + +#_______________________________________________________________________ +function _splitstr(A, t, r) +{ + ########################################### 1 # + if (_istr(t)) { + if (_splitstr_i0(A, t) > 0) { + return _splitstrp0 + } + if (_istr(r)) { + return _splitstr_i0(A, r) + } + } else { if (it == "A") { - if (length(r) > 0) { - _movarr(A, r) + if (length(t) > 0) { + _movarr(A, t) return (0 - length(A)) } } + _istr(r) } - - function _splitstr_i0(A, t, C) - { - #_____________________________________________________ - if (2 > (_splitstrq0 = patsplit(t, _SPLITSTRA0, /([^,\xB4]*\xB4.)*[^,\xB4]*/))) { - _splitstrq0 = split(gensub(/\xB4(.)/, "\\1", "G", t), _SPLITSTRA0, "") - } - delete A - _splitstri0 = _splitstrp0 = 0 - while (_splitstri0++ < _splitstrq0) { - if ((t = gensub(/\xB4(.)/, "\\1", "G", _SPLITSTRA0[_splitstri0])) in C || t == "") { - continue - } - C[A[++_splitstrp0] = t] - } - return _splitstrp0 - } - - function _strtorexp(t) - { - #_______________________________________________ - gsub(/[\\\.\?\*\+\-\(\)\{\}\[\]\^\$\/\|]/, "\\\\&", t) - t = split(t, _TOREXP_STRA, /[\x00-\x1F]/, _TOREXP_STRB) - _torexp_strt0 = "" - for (_torexp_stri0 = 1; _torexp_stri0 < t; _torexp_stri0++) { - _torexp_strt0 = _torexp_strt0 _TOREXP_STRA[_torexp_stri0] "\\" _QASC[_TOREXP_STRB[_torexp_stri0]] - } - return (_torexp_strt0 _TOREXP_STRA[_torexp_stri0]) - } - - function _subseqoff(r, B) - { - patsplit(r, B, /\x84[^\x94]*\x94/) - return gensub(/\x84[^\x94]*\x94/, "\204", "G", r) - } - - function _subseqon(B, r, F, f, s, e, q, i, A) - { - q = split(r, A, /\x84/) - r = "" - f = F[""] - for (i = 1; i < q; i++) { - #_conl("curr r==`" r "': A[" i "]=`" A[i] "'") - #s=s in F ? _th0(F[s],_conl("handler `" F[s] "' for `" s "' ost=`" substr(e,3,length(e)-3) "'")) : _th0(F[""],_conl("default handler for `" s "'")) - s = substr(e = B[i], 2, 1) - #_conl("`" f "'") - s = (s in F ? F[s] : F[""]) - r = r (@f(A[i])) (@s(substr(e, 3, length(e) - 3))) - } - return (r (@f(A[i]))) - } - - function _sysinfo(D, h) - { - #_____________________________________________________________________________ - # _rdreg(ARRAY,reg_path) - # Import into ARRAY the content of the whole registree tree with the higher point specified by reg_path. - # ARRAY will be filled by the strings with following format: - # - # HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck\InstallPath.STR=C:\Program Files (x86)\GnuWin32 - # where: - # HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck <- REG KEY PATH - # InstallPath <- DATA FIELD - # STR <- TYPE - # C:\Program Files (x86)\GnuWin32 <- VALUE - # TYPE: - # STR - REG_SZ (String Value) - # W32 - REG_DWORD (DWORD (32-bit) Value) - # W64 - REG_QWORD (QWORD (64-bit) Value) - # BIN - REG_BINARY (Binary Value) - # XSZ - REG_EXPAND_SZ (Expandable String Value) - # MSZ - REG_MULTI_SZ (Multi-String Value) - #_________________________________________________________________________________________ - # HKCR HKEY_CLASSES_ROOT - # HKCU HKEY_CURRENT_USER - # HKLM HKEY_LOCAL_MACHINE - # HKU HKEY_USERS - # HKCC HKEY_CURRENT_CONFIG - # HKPD HKEY_PERFORMANCE_DATA - #___________________________________________________________________________________ - #################################################################################### - ############################################################## - h = "wmic /NODE: \"" h "\" OS 2>NUL" - if (split(_cmd(h), _SYSINFOA0, /[\x0D\x0A]+/) == 3) { - _sysinfol0 = length(h = _SYSINFOA0[2]) + 1 - _sysinfoq0 = _sysinfoq1 = split(_SYSINFOA0[1], _SYSINFOA0, / +/, _SYSINFOB0) - while (--_sysinfoq0 > 0) { - D[_sysinfof0] = gensub(/^ +| +$/, "", "G", substr(h, _sysinfol0 = _sysinfol0 - (_sysinfol1 = length(_sysinfof0 = _SYSINFOA0[_sysinfoq0]) + length(_SYSINFOB0[_sysinfoq0])), _sysinfol1)) - } - return (_sysinfoq1 - 1) + if (it == "A") { + if (length(r) > 0) { + _movarr(A, r) + return (0 - length(A)) } } +} - function _tOBJ(c, t, P) - { - switch (c) { - case "_lib_CMDLN": - ######################################################### - #___________________________________________________________ - #___________________________________________________________ - return t - case "_lib_APPLY": - #___________________________________________________________ - return - case "_lib_HELP": - #___________________________________________________________ - return - case "_lib_NAMEVER": - #___________________________________________________________ - return _ln("_tOBJ 3.0") - case "_lib_BEGIN": - #___________________________________________________________ - return - case "_lib_END": - #___________________________________________________________ - return - case "_lib_CLEANUP": - return _tOBJ_CLEANUP() - } +#_____________________________________________________ +function _splitstr_i0(A, t, C) +{ + if (2 > (_splitstrq0 = patsplit(t, _SPLITSTRA0, /([^,\xB4]*\xB4.)*[^,\xB4]*/))) { + _splitstrq0 = split(gensub(/\xB4(.)/, "\\1", "G", t), _SPLITSTRA0, "") } - - function _tOBJ_CLEANUP(p) - { - for (p in UIDSDEL) { - #_______________________________________________________________________ - ############################################## - delete _ptr[p] - delete _tPREV[p] - delete _tPARENT[p] - delete _tNEXT[p] - delete _tFCHLD[p] - delete _tQCHLD[p] - delete _tLCHLD[p] - delete _TMP0[p] - delete _TMP1[p] - delete _tLINK[p] - delete _tCLASS[p] + delete A + _splitstri0 = _splitstrp0 = 0 + while (_splitstri0++ < _splitstrq0) { + if ((t = gensub(/\xB4(.)/, "\\1", "G", _SPLITSTRA0[_splitstri0])) in C || t == "") { + continue } + C[A[++_splitstrp0] = t] } + return _splitstrp0 +} - function _tabtospc(t, ts, xc, a, c, n, A, B) - { - if (! ts) { - #_______________________________________________________________________ - ################################## - ts = _TAB_STEP_DEFAULT - } - c = split("." t, A, /\t+/, B) - A[1] = substr(A[1], 2) - t = "" - for (n = 1; n <= c; n++) { - t = t A[n] _getchrln(" ", (xc = length(B[n]) * ts + int((a = xc + length(A[n])) / ts) * ts) - a) - } - return t +#_______________________________________________ +function _strtorexp(t) +{ + gsub(/[\\\.\?\*\+\-\(\)\{\}\[\]\^\$\/\|]/, "\\\\&", t) + t = split(t, _TOREXP_STRA, /[\x00-\x1F]/, _TOREXP_STRB) + _torexp_strt0 = "" + for (_torexp_stri0 = 1; _torexp_stri0 < t; _torexp_stri0++) { + _torexp_strt0 = _torexp_strt0 _TOREXP_STRA[_torexp_stri0] "\\" _QASC[_TOREXP_STRB[_torexp_stri0]] } + return (_torexp_strt0 _TOREXP_STRA[_torexp_stri0]) +} - function _tapi(p, f, p0, p1, p2, p3, c) - { - #___________________________________________________________________________________ - #################################################################################### - c = p - do { - if (f in _[c]["API"]) { - f = _[c]["API"][f] - return @f(p, p0, p1, p2, p3) - } - c = _[c]["CLASS"] - } while ("CLASS" in _[c]) - } +function _subseqoff(r, B) +{ + patsplit(r, B, /\x84[^\x94]*\x94/) + return gensub(/\x84[^\x94]*\x94/, "\204", "G", r) +} - function _tbframe(f, p, p0, p1) - { - #_____________________________________________________________________________ - ################################################## - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbframe_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f +function _subseqon(B, r, F, f, s, e, q, i, A) +{ + q = split(r, A, /\x84/) + r = "" + f = F[""] + for (i = 1; i < q; i++) { + s = substr(e = B[i], 2, 1) + #_conl("curr r==`" r "': A[" i "]=`" A[i] "'") + #s=s in F ? _th0(F[s],_conl("handler `" F[s] "' for `" s "' ost=`" substr(e,3,length(e)-3) "'")) : _th0(F[""],_conl("default handler for `" s "'")) + s = (s in F ? F[s] : F[""]) + #_conl("`" f "'") + r = r (@f(A[i])) (@s(substr(e, 3, length(e) - 3))) } + return (r (@f(A[i]))) +} - function _tbframe_i0(f, p, p0, p1, a) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbframe(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } +#_____________________________________________________________________________ +# _rdreg(ARRAY,reg_path) +# Import into ARRAY the content of the whole registree tree with the higher point specified by reg_path. +# ARRAY will be filled by the strings with following format: +# +# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck\InstallPath.STR=C:\Program Files (x86)\GnuWin32 +# where: +# HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GnuWin32\CoreUtils\5.3.0\pck <- REG KEY PATH +# InstallPath <- DATA FIELD +# STR <- TYPE +# C:\Program Files (x86)\GnuWin32 <- VALUE +# TYPE: +# STR - REG_SZ (String Value) +# W32 - REG_DWORD (DWORD (32-bit) Value) +# W64 - REG_QWORD (QWORD (64-bit) Value) +# BIN - REG_BINARY (Binary Value) +# XSZ - REG_EXPAND_SZ (Expandable String Value) +# MSZ - REG_MULTI_SZ (Multi-String Value) +#_________________________________________________________________________________________ - function _tbframex(f, p, p0, p1) - { - #_______________________________________________________________________ - ########################################### - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbframex_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbframex_i0(f, p, p0, p1) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbframex(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbpass(f, p, p0, p1) - { - #_____________________________________________________________________________ - ################################################### - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbpass_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbpass_i0(f, p, p0, p1, a) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbpass(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } +# HKCR HKEY_CLASSES_ROOT +# HKCU HKEY_CURRENT_USER +# HKLM HKEY_LOCAL_MACHINE +# HKU HKEY_USERS +# HKCC HKEY_CURRENT_CONFIG +# HKPD HKEY_PERFORMANCE_DATA - function _tbpassx(f, p, p0, p1) - { - #_____________________________________________________________________________ - ################################################## - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tbpassx_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tbpassx_i0(f, p, p0, p1) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tLCHLD ? _tmbpassx(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tbrochld(p, f, pp) - { - if (p) { - if (p in _tFCHLD) { - #_____________________________________________________________________________ - ################################################### # TEST!!! - f = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - if (p in _tPARENT) { - pp = _tPARENT[p] - delete _tPARENT[p] - if (p in _tPREV) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f - delete _tPREV[p] - } else { - _tFCHLD[pp] = f - } - for (; f in _tNEXT; f = _tNEXT[f]) { - _tPARENT[f] = pp - } - _tPARENT[f] = pp - if (p in _tNEXT) { - _tPREV[_tNEXT[f] = _tNEXT[p]] = f - delete _tNEXT[p] - } else { - _tLCHLD[pp] = f - } - _tQCHLD[pp] = _tQCHLD[pp] + _tQCHLD[p] - 1 - delete _tQCHLD[p] - return f - } else { - delete _tQCHLD[p] - if (p in _tPREV) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f - delete _tPREV[p] - } - for (; f in _tNEXT; f = _tNEXT[f]) { - delete _tPARENT[f] - } - delete _tPARENT[f] - if (p in _tNEXT) { - _tPREV[_tNEXT[f] = _tNEXT[p]] = f - delete _tNEXT[p] - } - return f - } - } else { - if (p in _tPARENT) { - pp = _tPARENT[p] - delete _tPARENT[p] - if (p in _tPREV) { - if (p in _tNEXT) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] - delete _tNEXT[p] - } else { - delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] - } - delete _tPREV[p] - _tQCHLD[pp]-- - } else { - if (p in _tNEXT) { - delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] - delete _tNEXT[p] - _tQCHLD[pp]-- - } else { - delete _tFCHLD[pp] - delete _tLCHLD[pp] - delete _tQCHLD[pp] - } - } - } else { - if (p in _tPREV) { - if (p in _tNEXT) { - _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] - delete _tNEXT[p] - } else { - delete _tNEXT[_tPREV[p]] - } - delete _tPREV[p] - } else { - if (p in _tNEXT) { - delete _tPREV[_tNEXT[p]] - delete _tNEXT[p] - } - } - } - } - } - return p - } - function _tbrunframe(f, p, p0, p1) - { - #_________________________________________________________________ - ################################### - return _tbframe((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunframex(f, p, p0, p1) - { - #_________________________________________________________________ - ################################## - return _tbframex((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunpass(f, p, p0, p1) - { - #_________________________________________________________________ - #################################### - return _tbpass((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tbrunpassx(f, p, p0, p1) - { - #_________________________________________________________________ - ################################### - return _tbpassx((f ? f : "_trunframe_i0"), p, p0, p1) - } - function _tdel(p, i) - { - if (p in _) { - #_____________________________________________________________________________ - ########################################################## - _texclude(p) - for (i in _ptr[p]) { - if (isarray(_ptr[p][i])) { - _tdel_i1(_ptr[p][i]) - } else { - if (i = _ptr[p][i]) { - _tdel(i) - } - } - } - if (p in _tFCHLD) { - i = _tFCHLD[p] - do { - i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) - } while (i) - } - delete _[p] - _UIDSDEL[p] - } - } - function _tdel_i0(p, i) - { - for (i in _ptr[p]) { - #_____________________________________________________ - if (isarray(_ptr[p][i])) { - _tdel_i1(_ptr[p][i]) - } else { - if (i = _ptr[p][i]) { - _tdel(i) - } - } - } - if (p in _tFCHLD) { - i = _tFCHLD[p] - do { - i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) - } while (i) - } - delete _[p] - _UIDSDEL[p] - } - function _tdel_i1(A, i) - { - for (i in A) { - #_____________________________________________________ - if (isarray(A[i])) { - _tdel_i1(A[i]) - } else { - if (i = A[i]) { - _tdel(i) - } - } - } - } - function _tdelete(p, v) - { - #_____________________________________________________________________________ - ####################################################### # REMAKE EXCLUDE - if (p) { - _wLCHLD(_tDELPTR, p) - } - return v - } - function _tdelitem(p) - { - if (p) { - if ("HOST" in _PTR[p] && "ITEMNAME" in _[p]) { - #_________________________________________________________________ - ############################################# - return _wLCHLD(_PTR[_PTR[p]["HOST"]]["ITEM"][_[p]["ITEMNAME"]], p) - } - _tdelete(p) - return p - } - } - function _tend(a, b) - { - #_______________________________________________________________________ - ##################################################### - if (b == "") { - return (_t_ENDF[_t_ENDF[0]] = a) - } else { - return (_t_ENDF[_t_ENDF[0] + a] = b) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#___________________________________________________________________________________ +#################################################################################### + + + + + + + + + + + + + + + + + + + + + + + +function _sysinfo(D, h) +{ + ############################################################## + h = "wmic /NODE: \"" h "\" OS 2>NUL" + if (split(_cmd(h), _SYSINFOA0, /[\x0D\x0A]+/) == 3) { + _sysinfol0 = length(h = _SYSINFOA0[2]) + 1 + _sysinfoq0 = _sysinfoq1 = split(_SYSINFOA0[1], _SYSINFOA0, / +/, _SYSINFOB0) + while (--_sysinfoq0 > 0) { + D[_sysinfof0] = gensub(/^ +| +$/, "", "G", substr(h, _sysinfol0 = _sysinfol0 - (_sysinfol1 = length(_sysinfof0 = _SYSINFOA0[_sysinfoq0]) + length(_SYSINFOB0[_sysinfoq0])), _sysinfol1)) } + return (_sysinfoq1 - 1) } +} - function _texclude(p, v, pp) - { - if (p in _) { +######################################################### + +function _tOBJ(c, t, P) +{ + switch (c) { + case "_lib_CMDLN": + #___________________________________________________________ + return t + #___________________________________________________________ + case "_lib_APPLY": + return + #___________________________________________________________ + case "_lib_HELP": + return + #___________________________________________________________ + case "_lib_NAMEVER": + return _ln("_tOBJ 3.0") + #___________________________________________________________ + case "_lib_BEGIN": + return + #___________________________________________________________ + case "_lib_END": + return + #___________________________________________________________ + case "_lib_CLEANUP": + return _tOBJ_CLEANUP() + } +} + +#_______________________________________________________________________ +function _tOBJ_CLEANUP(p) +{ + ############################################## + for (p in UIDSDEL) { + delete _ptr[p] + delete _tPREV[p] + delete _tPARENT[p] + delete _tNEXT[p] + delete _tFCHLD[p] + delete _tQCHLD[p] + delete _tLCHLD[p] + delete _TMP0[p] + delete _TMP1[p] + delete _tLINK[p] + delete _tCLASS[p] + } +} + +#_______________________________________________________________________ +function _tabtospc(t, ts, xc, a, c, n, A, B) +{ + ################################## + if (! ts) { + ts = _TAB_STEP_DEFAULT + } + c = split("." t, A, /\t+/, B) + A[1] = substr(A[1], 2) + t = "" + for (n = 1; n <= c; n++) { + t = t A[n] _getchrln(" ", (xc = length(B[n]) * ts + int((a = xc + length(A[n])) / ts) * ts) - a) + } + return t +} + +#___________________________________________________________________________________ +#################################################################################### + + + + + + + +function _tapi(p, f, p0, p1, p2, p3, c) +{ + c = p + do { + if (f in _[c]["API"]) { + f = _[c]["API"][f] + return @f(p, p0, p1, p2, p3) + } + c = _[c]["CLASS"] + } while ("CLASS" in _[c]) +} + +#_____________________________________________________________________________ +function _tbframe(f, p, p0, p1) +{ + ################################################## + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbframe_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbframe_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbframe(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_______________________________________________________________________ +function _tbframex(f, p, p0, p1) +{ + ########################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbframex_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbframex_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbframex(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbpass(f, p, p0, p1) +{ + ################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbpass_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbpass_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbpass(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbpassx(f, p, p0, p1) +{ + ################################################## + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tbpassx_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tbpassx_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tLCHLD ? _tmbpassx(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tbrochld(p, f, pp) +{ + ################################################### # TEST!!! + if (p) { + if (p in _tFCHLD) { + f = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + if (p in _tPARENT) { + pp = _tPARENT[p] + delete _tPARENT[p] + if (p in _tPREV) { + _tNEXT[_tPREV[f] = _tPREV[p]] = f + delete _tPREV[p] + } else { + _tFCHLD[pp] = f + } + for (; f in _tNEXT; f = _tNEXT[f]) { + _tPARENT[f] = pp + } + _tPARENT[f] = pp + if (p in _tNEXT) { + _tPREV[_tNEXT[f] = _tNEXT[p]] = f + delete _tNEXT[p] + } else { + _tLCHLD[pp] = f + } + _tQCHLD[pp] = _tQCHLD[pp] + _tQCHLD[p] - 1 + delete _tQCHLD[p] + return f + } else { + delete _tQCHLD[p] + if (p in _tPREV) { + _tNEXT[_tPREV[f] = _tPREV[p]] = f + delete _tPREV[p] + } + for (; f in _tNEXT; f = _tNEXT[f]) { + delete _tPARENT[f] + } + delete _tPARENT[f] + if (p in _tNEXT) { + _tPREV[_tNEXT[f] = _tNEXT[p]] = f + delete _tNEXT[p] + } + return f + } + } else { if (p in _tPARENT) { - #_____________________________________________________________________________ - ################################################### # TEST!!! pp = _tPARENT[p] delete _tPARENT[p] if (p in _tPREV) { if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] delete _tNEXT[p] } else { delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] } delete _tPREV[p] + _tQCHLD[pp]-- } else { if (p in _tNEXT) { delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] delete _tNEXT[p] + _tQCHLD[pp]-- } else { delete _tFCHLD[pp] delete _tLCHLD[pp] delete _tQCHLD[pp] - return p } } - --_tQCHLD[pp] } else { if (p in _tPREV) { if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p] delete _tNEXT[p] } else { delete _tNEXT[_tPREV[p]] @@ -5822,1426 +5735,1521 @@ } } } - return p - } - } - - function _tframe(fF, p, p0, p1, p2) - { - # _tDLINK progressive development: concrete _tDLINK function\processing algo; all frame's families support - #_____________________________________________________________________________ - ############################################### - delete _t_ENDF[++_t_ENDF[0]] - p = (_isptr(p) ? (isarray(fF) ? _tframe_i1(fF, p, p0, p1, p2) : _tframe_i0(fF, p, p0, p1, p2)) : "") - --_t_ENDF[0] - return p - } - - function _tframe0(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - #_____________________________________________________________________________ - ######################################### - if (isarray(f)) { - return _tframe0_i0(f, p) - } - _tframex_p0(A, f, 0) - return _th0(_tframe0_i0(A, p), --_TEND[_ARRLEN]) } } - - function _tframe0_i0(A, p, f) - { - if (p in _tLINK) { - #_______________________________________________ - _tframe_link = p - if ("`" in A) { - f = A["`"] - while (p in _tLINK) { - @f(p = _tLINK[p]) - } + return p +} + +#_________________________________________________________________ +function _tbrunframe(f, p, p0, p1) +{ + ################################### + return _tbframe((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunframex(f, p, p0, p1) +{ + ################################## + return _tbframex((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunpass(f, p, p0, p1) +{ + #################################### + return _tbpass((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tbrunpassx(f, p, p0, p1) +{ + ################################### + return _tbpassx((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_____________________________________________________________________________ +function _tdel(p, i) +{ + ########################################################## + if (p in _) { + _texclude(p) + for (i in _ptr[p]) { + if (isarray(_ptr[p][i])) { + _tdel_i1(_ptr[p][i]) } else { - while (p in _tLINK) { - p = _tLINK[p] + if (i = _ptr[p][i]) { + _tdel(i) } } - } else { - _tframe_link = "" } if (p in _tFCHLD) { - return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p])) + i = _tFCHLD[p] + do { + i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) + } while (i) } - return _tframe0_i2(A, ".", p) + delete _[p] + _UIDSDEL[p] } +} - function _tframe0_i1(A, p) - { - #_______________________________________________ - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe0_i0(A, p) _tframe0_i1(A, _tNEXT[p])) +#_____________________________________________________ +function _tdel_i0(p, i) +{ + for (i in _ptr[p]) { + if (isarray(_ptr[p][i])) { + _tdel_i1(_ptr[p][i]) + } else { + if (i = _ptr[p][i]) { + _tdel(i) + } } - return _tframe0_i0(A, p) } - - function _tframe0_i2(A, m, p) - { - #_______________________________________________ - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } + if (p in _tFCHLD) { + i = _tFCHLD[p] + do { + i = ((i in _tNEXT ? _tNEXT[i] : "")) _tdel_i0(i) + } while (i) + } + delete _[p] + _UIDSDEL[p] +} + +#_____________________________________________________ +function _tdel_i1(A, i) +{ + for (i in A) { + if (isarray(A[i])) { + _tdel_i1(A[i]) + } else { + if (i = A[i]) { + _tdel(i) } - m = A[m] - return @m(p) } } +} - function _tframe1(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - #_________________________________________________________________ - ############################# - if (isarray(f)) { - return _tframe1_i0(f, p, p0) - } - _tframex_p0(A, f, 1) - return _th0(_tframe1_i0(A, p, p0), --_TEND[_ARRLEN]) - } +#_____________________________________________________________________________ +function _tdelete(p, v) +{ + ####################################################### # REMAKE EXCLUDE + if (p) { + _wLCHLD(_tDELPTR, p) } + return v +} - function _tframe1_i0(A, p, p0) - { - #_______________________________________________ - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] +#_________________________________________________________________ +function _tdelitem(p) +{ + ############################################# + if (p) { + if ("HOST" in _PTR[p] && "ITEMNAME" in _[p]) { + return _wLCHLD(_PTR[_PTR[p]["HOST"]]["ITEM"][_[p]["ITEMNAME"]], p) } - if (p in _tFCHLD) { - return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0)) - } - return _tframe1_i2(A, ".", p, p0) + _tdelete(p) + return p } +} - function _tframe1_i1(A, p, p0) - { - #_______________________________________________ - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe1_i0(A, p, p0) _tframe1_i1(A, _tNEXT[p], p0)) - } - return _tframe1_i0(A, p, p0) +#_______________________________________________________________________ +function _tend(a, b) +{ + ##################################################### + if (b == "") { + return (_t_ENDF[_t_ENDF[0]] = a) + } else { + return (_t_ENDF[_t_ENDF[0] + a] = b) } +} - function _tframe1_i2(A, m, p, p0) - { - #_______________________________________________ - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return +#_____________________________________________________________________________ +function _texclude(p, v, pp) +{ + ################################################### # TEST!!! + if (p in _) { + if (p in _tPARENT) { + pp = _tPARENT[p] + delete _tPARENT[p] + if (p in _tPREV) { + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + delete _tNEXT[p] + } else { + delete _tNEXT[_tLCHLD[pp] = _tPREV[p]] + } + delete _tPREV[p] + } else { + if (p in _tNEXT) { + delete _tPREV[_tFCHLD[pp] = _tNEXT[p]] + delete _tNEXT[p] + } else { + delete _tFCHLD[pp] + delete _tLCHLD[pp] + delete _tQCHLD[pp] + return p } } - m = A[m] - return @m(p, p0) - } - } - - function _tframe2(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - #_________________________________________________________________ - ############################# - if (isarray(f)) { - return _tframe2_i0(f, p, p0, p1) + --_tQCHLD[pp] + } else { + if (p in _tPREV) { + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v = _tPREV[p] + delete _tNEXT[p] + } else { + delete _tNEXT[_tPREV[p]] + } + delete _tPREV[p] + } else { + if (p in _tNEXT) { + delete _tPREV[_tNEXT[p]] + delete _tNEXT[p] + } } - _tframex_p0(A, f, 2) - return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN]) } + return p } - - function _tframe2_i0(A, p, p0, p1) - { - #_______________________________________________ +} + +# _tDLINK progressive development: concrete _tDLINK function\processing algo; all frame's families support +#_____________________________________________________________________________ +function _tframe(fF, p, p0, p1, p2) +{ + ############################################### + delete _t_ENDF[++_t_ENDF[0]] + p = (_isptr(p) ? (isarray(fF) ? _tframe_i1(fF, p, p0, p1, p2) : _tframe_i0(fF, p, p0, p1, p2)) : "") + --_t_ENDF[0] + return p +} + +#_____________________________________________________________________________ +function _tframe0(f, p, p0, p1, p2, p3, A) +{ + ######################################### + if (_isptr(p)) { + if (isarray(f)) { + return _tframe0_i0(f, p) + } + _tframex_p0(A, f, 0) + return _th0(_tframe0_i0(A, p), --_TEND[_ARRLEN]) + } +} + +#_______________________________________________ +function _tframe0_i0(A, p, f) +{ + if (p in _tLINK) { _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] - } - if (p in _tFCHLD) { - return (_tframe2_i2(A, "^", p, p0, p1) _tframe2_i1(A, _tFCHLD[p], p0, p1)) + if ("`" in A) { + f = A["`"] + while (p in _tLINK) { + @f(p = _tLINK[p]) + } + } else { + while (p in _tLINK) { + p = _tLINK[p] + } } - return _tframe2_i2(A, ".", p, p0, p1) + } else { + _tframe_link = "" } - - function _tframe2_i1(A, p, p0, p1) - { - #_______________________________________________ - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe2_i0(A, p, p0, p1) _tframe2_i1(A, _tNEXT[p], p0, p1)) - } - return _tframe2_i0(A, p, p0, p1) + if (p in _tFCHLD) { + return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p])) } + return _tframe0_i2(A, ".", p) +} - function _tframe2_i2(A, m, p, p0, p1) - { - #_______________________________________________ - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } - } - m = A[m] - return @m(p, p0, p1) - } +#_______________________________________________ +function _tframe0_i1(A, p) +{ + if (_TEND[_ARRLEN] in _TEND) { + return + } + if (p in _tNEXT) { + return (_tframe0_i0(A, p) _tframe0_i1(A, _tNEXT[p])) } + return _tframe0_i0(A, p) +} - function _tframe3(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - #_________________________________________________________________ - ############################# - if (isarray(f)) { - return _tframe3_i0(f, p, p0, p1, p2) +#_______________________________________________ +function _tframe0_i2(A, m, p) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] + } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - _tframex_p0(A, f, 3) - return _th0(_tframe3_i0(A, p, p0, p1, p2), --_TEND[_ARRLEN]) } + m = A[m] + return @m(p) } +} - function _tframe3_i0(A, p, p0, p1, p2) - { - #_______________________________________________ - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] +#_________________________________________________________________ +function _tframe1(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe1_i0(f, p, p0) } - if (p in _tFCHLD) { - return (_tframe3_i2(A, "^", p, p0, p1, p2) _tframe3_i1(A, _tFCHLD[p], p0, p1, p2)) - } - return _tframe3_i2(A, ".", p, p0, p1, p2) + _tframex_p0(A, f, 1) + return _th0(_tframe1_i0(A, p, p0), --_TEND[_ARRLEN]) } +} - function _tframe3_i1(A, p, p0, p1, p2) - { - #_______________________________________________ - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe3_i0(A, p, p0, p1, p2) _tframe3_i1(A, _tNEXT[p], p0, p1, p2)) - } - return _tframe3_i0(A, p, p0, p1, p2) +#_______________________________________________ +function _tframe1_i0(A, p, p0) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _tframe3_i2(A, m, p, p0, p1, p2) - { - #_______________________________________________ - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } - } - m = A[m] - return @m(p, p0, p1, p2) - } + if (p in _tFCHLD) { + return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0)) } + return _tframe1_i2(A, ".", p, p0) +} - function _tframe4(f, p, p0, p1, p2, p3, A) - { - if (_isptr(p)) { - #_________________________________________________________________ - ############################# - if (isarray(f)) { - return _tframe4_i0(f, p, p0, p1, p2, p3) - } - _tframex_p0(A, f, 4) - return _th0(_tframe4_i0(A, p, p0, p1, p2, p3), --_TEND[_ARRLEN]) - } +#_______________________________________________ +function _tframe1_i1(A, p, p0) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } - - function _tframe4_i0(A, p, p0, p1, p2, p3) - { - #_______________________________________________ - _tframe_link = p - while (p in _tLINK) { - p = _tLINK[p] - } - if (p in _tFCHLD) { - return (_tframe4_i2(A, "^", p, p0, p1, p2, p3) _tframe4_i1(A, _tFCHLD[p], p0, p1, p2, p3)) - } - return _tframe4_i2(A, ".", p, p0, p1, p2, p3) + if (p in _tNEXT) { + return (_tframe1_i0(A, p, p0) _tframe1_i1(A, _tNEXT[p], p0)) } + return _tframe1_i0(A, p, p0) +} - function _tframe4_i1(A, p, p0, p1, p2, p3) - { - #_______________________________________________ - if (_TEND[_ARRLEN] in _TEND) { - return - } - if (p in _tNEXT) { - return (_tframe4_i0(A, p, p0, p1, p2, p3) _tframe4_i1(A, _tNEXT[p], p0, p1, p2, p3)) - } - return _tframe4_i0(A, p, p0, p1, p2, p3) +#_______________________________________________ +function _tframe1_i2(A, m, p, p0) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tframe4_i2(A, m, p, p0, p1, p2, p3) - { - #_______________________________________________ - _tframe_dlink = p - while (p in _tDLINK) { - p = _tDLINK[p] - } - if (m in A) { - if (m "~" in A) { - if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { - return - } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - m = A[m] - return @m(p, p0, p1, p2, p3) - } - } - - function _tframe_i0(f, p, p0, p1, p2, a) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] } - return ((p in _tFCHLD ? _tmframe_i0(f, _tFCHLD[p], p0, p1, p2) : (p in _tDLINK ? @f(_tDLINK[p], p0, p1, p2) : @f(p, p0, p1, p2)))) + m = A[m] + return @m(p, p0) } +} - function _tframe_i1(F, p, p0, p1, p2, a) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] +#_________________________________________________________________ +function _tframe2(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe2_i0(f, p, p0, p1) } - return ((p in _tFCHLD ? (("." in F ? _th1(a = F["."], @a(p, p0, p1, p2)) : "")) _tmframe_i1(F, _tFCHLD[p], p0, p1, p2) : (">" in F ? _th1(a = F[">"], (p in _tDLINK ? @a(_tDLINK[p], p0, p1, p2) : @a(p, p0, p1, p2))) : ""))) + _tframex_p0(A, f, 2) + return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN]) } +} - function _tframex(f, p, p0, p1) - { - #_______________________________________________________________________ - ############################################ - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tframex_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f +#_______________________________________________ +function _tframe2_i0(A, p, p0, p1) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _tframex_i0(f, p, p0, p1) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmframex(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) + if (p in _tFCHLD) { + return (_tframe2_i2(A, "^", p, p0, p1) _tframe2_i1(A, _tFCHLD[p], p0, p1)) } + return _tframe2_i2(A, ".", p, p0, p1) +} - function _tframex_p0(A, f, q, i, B, C) - { - #_____________________________________________________ - _tframe_qparam = q - delete _TEND[++_TEND[_ARRLEN]] - if (match(f, /\~(.*)$/, B)) { - A["^~"] = A[".~"] = B[1] - f = substr(f, 1, RSTART - 1) - } - A["."] = A["^"] = f +#_______________________________________________ +function _tframe2_i1(A, p, p0, p1) +{ + if (_TEND[_ARRLEN] in _TEND) { return - q = split(f, B, /;/) - i = 0 - while (i < q) { - _tframex_p1(A, C[i]) - while (++i <= q) { - _tframex_p1(A, C[i], B[i]) - } - } } - - function _tframex_p1(A, v, i, r, B) - { - #_______________________________________________ - gsub(/[ \t]+/, "", v) - while (match(v, /^([^~]*)~\/(([^\/\\]*\\.)*[^\/\\]*)\//, B)) { - v = B[1] substr(v, RSTART + RLENGTH) - r = B[2] - } - if (i == "") { - if (v != "") { - A["."] = v - delete A["`"] - delete A["^"] - } - if (r != "") { - A[".~"] = A["`~"] = A["^~"] = r - } - } else { - if (match(v, /!/)) { - delete A[i] - } else { - A[i] = v - if (r != "") { - A[i "~"] = r - } - } - } + if (p in _tNEXT) { + return (_tframe2_i0(A, p, p0, p1) _tframe2_i1(A, _tNEXT[p], p0, p1)) } + return _tframe2_i0(A, p, p0, p1) +} - function _tgenuid(c) - { - for (_uidcntr in _UIDARR1) { - #_____________________________________________________ - # F v action - #----------------------------------------------------- - # - * no additional action - # A B delete A[p] and define A[p] as array; copy array B to array A[p] - # A - delete A[p] - # A "*" delete A[p]; A[p]="*" - # "*" B define _[p]["*"] as array; copy array B to array _[p]["*"] - # "*" - run _mpu program "*" for `p - # "*0" "*1" _[p]["*0"]="*1" - #___________________________________________________________ - delete _UIDARR1[_uidcntr] - for (c in _UIDARR0) { - _UIDS[_uidcntr c] - } - delete _UIDS[_uidcntr c] - return (_uidcntr c) - } - return _fatal("_tUID: Out of UID range") +#_______________________________________________ +function _tframe2_i2(A, m, p, p0, p1) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tgenuid_init(a, b, A) - { - #_____________________________________________________ - _ptrlength = 4 - a = "\222\223\224\225\226\227\230\231\232" "\240\241\242\243\244\245\246\247" "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" - split(a, A, "") - for (a in A) { - for (b in A) { - _UIDARR0[A[a] A[b]] _UIDARR1[A[a] A[b]] + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } } - _uidcntr = A[a] A[b] + m = A[m] + return @m(p, p0, p1) } +} - function _tgetitem(p, n, a, b) - { - if (p) { - # if ( F in _TCLASS ) { _[p]["CLASS"]=_TCLASS[F]; _tapi(p); return p } - # # ??? _mpu(F,p) ??? - # return p } - # _[p][F]=v; return p } - #_______________________________________________________________________ - ############################################ - if (isarray(_PTR[p]["ITEM"]) && n in _PTR[p]["ITEM"]) { - a = _PTR[p]["ITEM"][n] - } else { - a = _PTR[p]["ITEM"][n] = _N() - } - if (! (b = _rFCHLD(a))) { - b = _wLCHLD(a, _N()) - _PTR[b]["HOST"] = p - _[b]["ITEMNAME"] = n - } - return b +#_________________________________________________________________ +function _tframe3(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe3_i0(f, p, p0, p1, p2) } + _tframex_p0(A, f, 3) + return _th0(_tframe3_i0(A, p, p0, p1, p2), --_TEND[_ARRLEN]) } +} - function _tgetsp(p) - { - #_________________________________________________________________ - ############################################### - return _tSTACK[p][0] - } - - function _th0(p, p1, p2, p3) - { - #################################################################################### - #_____________________________________________________________________________ - return p - } - - function _th1(p0, p, p2, p3) - { - ########################################## - #_________________________________________________________________ - return p +#_______________________________________________ +function _tframe3_i0(A, p, p0, p1, p2) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] } - - function _th10(p0, p1) - { - ############################## - #_________________________________________________________________ - return (p1 p0) + if (p in _tFCHLD) { + return (_tframe3_i2(A, "^", p, p0, p1, p2) _tframe3_i1(A, _tFCHLD[p], p0, p1, p2)) } + return _tframe3_i2(A, ".", p, p0, p1, p2) +} - function _th2(p0, p1, r, p3) - { - ############################## - #_________________________________________________________________ - return p +#_______________________________________________ +function _tframe3_i1(A, p, p0, p1, p2) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } - - function _th3(p0, p1, p2, r) - { - ############################## - #_________________________________________________________________ - return p + if (p in _tNEXT) { + return (_tframe3_i0(A, p, p0, p1, p2) _tframe3_i1(A, _tNEXT[p], p0, p1, p2)) } + return _tframe3_i0(A, p, p0, p1, p2) +} - function _tifend(l) - { - #_________________________________________________________________ - ############################################### - return ((_t_ENDF[0] + l in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : "")) +#_______________________________________________ +function _tframe3_i2(A, m, p, p0, p1, p2) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] } - - function _tinit_i0(D, S, i) - { - for (i in S) { - if (isarray(S[i])) { - if (! isarray(D[i][""])) { - # test _tbrochld fn; develope tOBJ r\w func specification for brochld func - #_________________________________________________________________ - delete D[i] - D[i][""] - delete D[i][""] - } - _N_i0(D[i], S[i]) - } else { - if (isarray(D[i])) { - delete D[i] - } - D[i] = S[i] + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } } + m = A[m] + return @m(p, p0, p1, p2) } +} - function _tlist(L, p, f) - { - #_______________________________________________________________________ - ######################################################################## - #_______________________________________________________________________ - # _N(arr\str\mpuptr,val) \ _n(arr\str\mpuptr,val) - # This functions create new object and return ptr. - # _n() - creates object from list of deleted objects or if it's empty create new one, while _N() always create new one - # It is strongly recommended to use _N() for the objects that have some data outside of standart object arrays. Or - make routines - # that will clear outsided object data in case if object deleting. - # - # IN: arr\str\mpu,val - (both missed) just create obj and return ptr - # arr,val - create object and write arr[ptr]=val - # str,val - create object and write _[ptr][str]=val - # mpuptr - NOT ALLOWED (val missed) create object and run MPU-code specified by mpuptr with created object ptr as primary parameter - # MOD: - - # OUT: - - # RETURN: ptr - pointer to newly created object - #_________________________________________________________________ - # _tdel(ptr) - # This function exclude object from it's current structure and delete it. ptr can be later used by function: _n() for creating new object - # Also same story will occured with all chields and subchields of object specified by ptr. - # ??? What happened with linked py _ptr[ptr] objects ??? - # - # IN: ptr - pointer to object that will deleted - # MOD: - - # OUT: - - # RETURN: undefined - #_________________________________________________________________ - # _isptr(ptr) - # This function checks: is ptr is the object pointer that is currently exist? - # Unescaped remained data will be in data of src_dst_ptr. - # - # IN: ptr - string that will be tested - # MOD: - - # OUT: - - # RETURN: undefined - if ptr is not pointer to exist object - # ptr - if ptr is the pointer to exist object - #_________________________________________________________________ - #_________________________________________________________________ - # - # TO DESIGN: - # - # create basic objectapi interface support - # modify everywhere checking ptr not by `if ( ptr )...', but by `if ( ptr in _ )...' - # _TMP0, _TMP1 name change to something like _DATA name ??? - # think about redesigning routines for not depending if ptr is exist in tsysarrs: reason: performance\light code - _tlisti1 = _tlisti0 = L[_ARRLEN] + 0 - if (f == 0 && f == "") { - _tlist_i0(L, p) - } else { - _tlistf0 = (f in _TAPI ? _TAPI[f] : f) - _tlist_i1(L, p) +#_________________________________________________________________ +function _tframe4(f, p, p0, p1, p2, p3, A) +{ + ############################# + if (_isptr(p)) { + if (isarray(f)) { + return _tframe4_i0(f, p, p0, p1, p2, p3) } - return (_tlisti0 - _tlisti1) + _tframex_p0(A, f, 4) + return _th0(_tframe4_i0(A, p, p0, p1, p2, p3), --_TEND[_ARRLEN]) } +} - function _tlist_i0(L, p, q, i) - { - if (isarray(p)) { - q = p[_ARRLEN] - i = 0 - while (i++ < q) { - _tlist_i0(L, p[i]) - } - return - } - if (p in _) { - while (p in _tLINK) { - p = _tLINK[p] - } - L[++_tlisti0] = p - if (p in _tFCHLD) { - for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { - _tlist_i0(L, p) - } - } - } +#_______________________________________________ +function _tframe4_i0(A, p, p0, p1, p2, p3) +{ + _tframe_link = p + while (p in _tLINK) { + p = _tLINK[p] + } + if (p in _tFCHLD) { + return (_tframe4_i2(A, "^", p, p0, p1, p2, p3) _tframe4_i1(A, _tFCHLD[p], p0, p1, p2, p3)) + } + return _tframe4_i2(A, ".", p, p0, p1, p2, p3) +} + +#_______________________________________________ +function _tframe4_i1(A, p, p0, p1, p2, p3) +{ + if (_TEND[_ARRLEN] in _TEND) { + return } + if (p in _tNEXT) { + return (_tframe4_i0(A, p, p0, p1, p2, p3) _tframe4_i1(A, _tNEXT[p], p0, p1, p2, p3)) + } + return _tframe4_i0(A, p, p0, p1, p2, p3) +} - function _tlist_i1(L, p) - { - if (isarray(p)) { - q = p[_ARRLEN] - i = 0 - while (i++ < q) { - _tlist_i1(L, p[i]) +#_______________________________________________ +function _tframe4_i2(A, m, p, p0, p1, p2, p3) +{ + _tframe_dlink = p + while (p in _tDLINK) { + p = _tDLINK[p] + } + if (m in A) { + if (m "~" in A) { + if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) { + return } - return } - if (p in _) { - while (p in _tLINK) { - p = _tLINK[p] - } - if (_tlistf0 in _[p]) { - L[++_tlisti0] = p + m = A[m] + return @m(p, p0, p1, p2, p3) + } +} + +#___________________________________________________________ +function _tframe_i0(f, p, p0, p1, p2, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmframe_i0(f, _tFCHLD[p], p0, p1, p2) : (p in _tDLINK ? @f(_tDLINK[p], p0, p1, p2) : @f(p, p0, p1, p2)))) +} + +#___________________________________________________________ +function _tframe_i1(F, p, p0, p1, p2, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? (("." in F ? _th1(a = F["."], @a(p, p0, p1, p2)) : "")) _tmframe_i1(F, _tFCHLD[p], p0, p1, p2) : (">" in F ? _th1(a = F[">"], (p in _tDLINK ? @a(_tDLINK[p], p0, p1, p2) : @a(p, p0, p1, p2))) : ""))) +} + +#_______________________________________________________________________ +function _tframex(f, p, p0, p1) +{ + ############################################ + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tframex_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tframex_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmframex(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________ +function _tframex_p0(A, f, q, i, B, C) +{ + _tframe_qparam = q + delete _TEND[++_TEND[_ARRLEN]] + if (match(f, /\~(.*)$/, B)) { + A["^~"] = A[".~"] = B[1] + f = substr(f, 1, RSTART - 1) + } + A["."] = A["^"] = f + return + q = split(f, B, /;/) + i = 0 + while (i < q) { + _tframex_p1(A, C[i]) + while (++i <= q) { + _tframex_p1(A, C[i], B[i]) + } + } +} + +#_______________________________________________ +function _tframex_p1(A, v, i, r, B) +{ + gsub(/[ \t]+/, "", v) + while (match(v, /^([^~]*)~\/(([^\/\\]*\\.)*[^\/\\]*)\//, B)) { + v = B[1] substr(v, RSTART + RLENGTH) + r = B[2] + } + if (i == "") { + if (v != "") { + A["."] = v + delete A["`"] + delete A["^"] + } + if (r != "") { + A[".~"] = A["`~"] = A["^~"] = r + } + } else { + if (match(v, /!/)) { + delete A[i] + } else { + A[i] = v + if (r != "") { + A[i "~"] = r + } + } + } +} + +#_____________________________________________________ +# F v action +#----------------------------------------------------- +# - * no additional action +# A B delete A[p] and define A[p] as array; copy array B to array A[p] +# A - delete A[p] +# A "*" delete A[p]; A[p]="*" +# "*" B define _[p]["*"] as array; copy array B to array _[p]["*"] +# "*" - run _mpu program "*" for `p +# "*0" "*1" _[p]["*0"]="*1" +#___________________________________________________________ +function _tgenuid(c) +{ + for (_uidcntr in _UIDARR1) { + delete _UIDARR1[_uidcntr] + for (c in _UIDARR0) { + _UIDS[_uidcntr c] + } + delete _UIDS[_uidcntr c] + return (_uidcntr c) + } + return _fatal("_tUID: Out of UID range") +} + +#_____________________________________________________ +function _tgenuid_init(a, b, A) +{ + _ptrlength = 4 + a = "\222\223\224\225\226\227\230\231\232" "\240\241\242\243\244\245\246\247" "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + split(a, A, "") + for (a in A) { + for (b in A) { + _UIDARR0[A[a] A[b]] _UIDARR1[A[a] A[b]] + } + } + _uidcntr = A[a] A[b] +} + +# if ( F in _TCLASS ) { _[p]["CLASS"]=_TCLASS[F]; _tapi(p); return p } +# # ??? _mpu(F,p) ??? +# return p } +# _[p][F]=v; return p } + +#_______________________________________________________________________ +function _tgetitem(p, n, a, b) +{ + ############################################ + if (p) { + if (isarray(_PTR[p]["ITEM"]) && n in _PTR[p]["ITEM"]) { + a = _PTR[p]["ITEM"][n] + } else { + a = _PTR[p]["ITEM"][n] = _N() + } + if (! (b = _rFCHLD(a))) { + b = _wLCHLD(a, _N()) + _PTR[b]["HOST"] = p + _[b]["ITEMNAME"] = n + } + return b + } +} + +#_________________________________________________________________ +function _tgetsp(p) +{ + ############################################### + return _tSTACK[p][0] +} + +#################################################################################### + +#_____________________________________________________________________________ +function _th0(p, p1, p2, p3) +{ + return p +} + +########################################## +#_________________________________________________________________ +function _th1(p0, p, p2, p3) +{ + return p +} + +############################## +#_________________________________________________________________ +function _th10(p0, p1) +{ + return (p1 p0) +} + +############################## +#_________________________________________________________________ +function _th2(p0, p1, r, p3) +{ + return p +} + +############################## +#_________________________________________________________________ +function _th3(p0, p1, p2, r) +{ + return p +} + +#_________________________________________________________________ +function _tifend(l) +{ + ############################################### + return ((_t_ENDF[0] + l in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : "")) +} + +# test _tbrochld fn; develope tOBJ r\w func specification for brochld func + +#_________________________________________________________________ +function _tinit_i0(D, S, i) +{ + for (i in S) { + if (isarray(S[i])) { + if (! isarray(D[i][""])) { + delete D[i] + D[i][""] + delete D[i][""] } - if (p in _tFCHLD) { - for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { - _tlist_i1(L, p) - } + _N_i0(D[i], S[i]) + } else { + if (isarray(D[i])) { + delete D[i] } + D[i] = S[i] } } +} - function _tmbframe(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ################################## - t = t _tbframe_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) - } - return t - } +#_______________________________________________________________________ +######################################################################## - function _tmbframex(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ################################# - t = t _tbframex_i0(f, p, p0, p1) - p = (p in _tPREV ? _tPREV[p] : "") - } - return t - } - function _tmbpass(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ###################################### - p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) - } - return p0 - } - function _tmbpassx(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ##################################### - p0 = _tbpassx_i0(f, p, p0, p1) - p = (p in _tPREV ? _tPREV[p] : "") - } - return p0 - } - function _tmframe(f, p, p0, p1, p2) - { - #_________________________________________________________________ - ################################### - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tmframe_i0(f, p, p0, p1, p2) : "") - --_t_ENDF[0] - return f - } - function _tmframe_i0(f, p, p0, p1, p2, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #___________________________________________________________ - t = t _tframe_i0(f, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return t - } - function _tmframe_i1(F, p, p0, p1, p2, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #___________________________________________________________ - t = t _tframe_i1(F, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return t - } - function _tmframex(f, p, p0, p1, t) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ################################## - t = t _tframex_i0(f, p, p0, p1) - p = (p in _tNEXT ? _tNEXT[p] : "") - } - return t - } - function _tmpass(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ####################################### - p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tNEXT ? _tNEXT[p] : "")) - } - return p0 - } - function _tmpassx(f, p, p0, p1) - { - while (p && ! (_t_ENDF[0] in _t_ENDF)) { - #_________________________________________________________________ - ###################################### - p0 = _tbpassx_i0(f, p, p0, p1) - p = (p in _tNEXT ? _tNEXT[p] : "") - } - return p0 - } - function _torexp(r) - { - return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN) - } - function _torexp_cmdstr(t) - { - return _strtorexp(gensub(/\^(.)/, "\\1", "G", t)) - } - function _torexp_fmask(t) - { - return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t))) - } - function _torexp_init() - { - #_______________________________________________ - _TOREXPFN[""] = "_strtorexp" - _TOREXPFN["~"] = "_torexp_rexp" - _TOREXPFN["="] = "_strtorexp" - _TOREXPFN[">"] = "_torexp_cmdstr" - _TOREXPFN["#"] = "_torexp_fmask" - _TOREXPFN["\""] = "_torexp_dqstr" - _TOREXPFN["'"] = "_torexp_sqstr" - } - function _torexp_rexp(t) - { - #_______________________________________________ - return t - } - function _tpass(f, p, p0, p1) - { - #_____________________________________________________________________________ - #################################################### - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tpass_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tpass_i0(f, p, p0, p1, a) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tpassx(f, p, p0, p1) - { - #_____________________________________________________________________________ - ################################################### - delete _t_ENDF[++_t_ENDF[0]] - f = (p ? _tpassx_i0(f, p, p0, p1) : "") - --_t_ENDF[0] - return f - } - function _tpassx_i0(f, p, p0, p1) - { - #___________________________________________________________ - while (p in _tLINK) { - p = _tLINK[p] - } - return ((p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) - } - function _tpop(p, aA, a) - { - if ((a = _tSTACK[p][0]) > 0) { - #_________________________________________________________________ - ########################################### - _tSTACK[p][0]-- - if (isarray(_tSTACK[p][a])) { - delete aA - _movarr(aA, _tSTACK[p][a]) - return - } - return _tSTACK[p][a] - } - _fatal("^" p ": Out of tSTACK") - } - function _tpush(p, aA, a) - { - if (isarray(aA)) { - #_____________________________________________________________________________ - ###################################################### - delete _tSTACK[p][a = ++_tSTACK[p][0]] - _tSTACK[p][a][""] - delete _tSTACK[p][a][""] - _movarr(_tSTACK[p][a], aA) - return - } - delete _tSTACK[p][a = ++_tSTACK[p][0]] - return (_tSTACK[p][a] = aA) - } - - function _tr(n, cs, H) - { - # prefix - - # prichr - aware character `{', `^',`]' - # sechr - aware character `.' as the first char of sechr, and character `}' - # suffix - aware character `]' - # cntptr - aware character `]' - #_tuidinitcs[p]=cs - #2 uidel, 5 pfx, 7 hichr,11(10) lochr,14 suffix - _rconline(n ": " cs) - _rconl() - if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) { - _rconl("delptr: " _une(H[2]) "'") - _rconl("pfxstr: " _une(H[5]) "'") - _rconl("hichr: " _une(H[7]) "'") - _rconl("lochr: " _une((H[10] ? H[7] "' and " H[11] "'" : H[11] "'"))) - _rconl("sfxstr: " _une(H[14]) "'") - } else { - _rconl("NOT MATCH!") - } - _rconl() - } - - function _trace(t, d, A) - { - if (_ERRLOG_TF) { - #_______________________________________________________________________ - ################################################# - A["TYPE"] = "TRACE" - A["TEXT"] = t - _log(A, d) - } - } - - function _trunframe(f, p, p0, p1, p2) - { - #_________________________________________________________________ - ################################# - return _tframe((f ? f : "_trunframe_i0"), p, p0, p1, p2) - } - - function _trunframe_i0(p, p0, p1, p2, f) - { - if (p in _tFN) { - #_________________________________________________________________ - f = _tFN[p] - return @f(p, p0, p1, p2) - } - } - - function _trunframex(f, p, p0, p1) - { - #_________________________________________________________________ - ################################### - return _tframex((f ? f : "_trunframe_i0"), p, p0, p1) - } - - function _trunpass(f, p, p0, p1) - { - #_________________________________________________________________ - ##################################### - return _tpass((f ? f : "_trunframe_i0"), p, p0, p1) - } - - function _trunpassx(f, p, p0, p1) - { - #_________________________________________________________________ - #################################### - return _tpassx((f ? f : "_trunframe_i0"), p, p0, p1) - } - - function _tsetsp(p, v) - { - #_________________________________________________________________ - ############################################# - return (_tSTACK[p][0] = v) - } - - function _tstini() - { - # dptr - morg ptr; in case if object deleted then _CLASSPTR[ptr] will be deleted(object is death), but - # _tUIDEL[_CLASSPTR[ptr]] will be created that object can be resurrected from morg - # dptr can be any string containing any characters except `:'. It's not verified - # pfx,sfx - uid prefix str, and uid suffix str; this strings specifies string that can be inserted before/after - # uid generated by uid generator: - # - # class uid: pfx uidgen sfx - # - # Both can be any string(including ""), and can contains any character with B4-escaping feature. - # Note: that this strings cannot contains "'" character: it's should be escaped by B4-escaper. - # hstr,lstr - this values configure uid-generator itself. ther is a 3 combinations regarding its: - # - # hstr lstr function - # - # `ptr * - specify pointer to external uid-generator - # All uids and chars will be generated by external uid-generator - # * ^ptr - class will have it's own uid generator using external character set - # str str - class will have it's own uid generator with it's own character set - # character set inmplemented in hstr(high-charset) and in lstr(low-charset) in 2 ways: - # 1) "AB" "AB01" - this mean that high-charset contain chars: `A' and `B' - # low-charset contains chars: `A', `B', `0', `1' - # - # 2) "Az,By" "Ax,Bw,0v,1u" - this mean that high-charset contain chars: `Az' and `By' - # low-charset contains chars: `Ax', `Bw', `0v', `1u' - # Note: both: hstr and lstr cannot contain char `,' directly, but it's can uses - # B4-escaper to escape any char including `,' - # !!!! in case of using `,' in hstr/lstr - the escaped `,' will leads to interpretate hstr and lstr as divided by `,' - # if parameters error then i should be more specific about what error in parameters detected - # document _inituid(): parameters; document cs: uid initialization string format - # test with escape char - # adv hstr and lstr splitting? - # chk if hstr len==0 ? - # return _tclass & report error? - # _tapi thru function - # additional syntax checking ??? - # implement syntax and uid srv in docs - # add _dumpuid() ???? - # make performance measurement - # protection against badchar list - # additional feature to specify _getuid() to not resurrect uid; and informative that uid was ressurected or not - # build _defclass fn - # _tuidinitcs ???? - # _tuidchrh[p] - # _tuidchrl[p] - # _tuidchr[p] - # _tuidcnt[p] - # _tUIDPFX[p] - # _tUIDSFX[p] - # _tUIDEL - # _tUIDCNTH - # _tUIDCNTL - # _tUIDCHRL - # _tUIDCHRH - # create default class basic `new' and `del' functions - _ini("uidel:pfx'hstr|lstr'sfx") - _ini("uidel:pfx'hstr|lstr'") - _ini("uidel:'hstr|lstr'sfx") - _ini("uidel:'hstr|lstr'") - _ini("uidel:pfx'hstr'sfx") - _ini("uidel:pfx'hstr'") - _ini("uidel:'hstr'sfx") - _ini("uidel:'hstr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'hstr|lstr'sfx") - _ini("pfx'hstr|lstr'") - _ini("'hstr|lstr'sfx") - _ini("'hstr|lstr'") - _ini("pfx'hstr'sfx") - _ini("pfx'hstr'") - _ini("'hstr'sfx") - _ini("'hstr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("uidel:pfx'`cntptr'sfx") - _ini("uidel:pfx'`cntptr'") - _ini("uidel:'`cntptr'sfx") - _ini("uidel:'`cntptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'`cntptr'sfx") - _ini("pfx'`cntptr'") - _ini("'`cntptr'sfx") - _ini("'`cntptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("uidel:pfx'^chrptr'sfx") - _ini("uidel:pfx'^chrptr'") - _ini("uidel:'^chrptr'sfx") - _ini("uidel:'^chrptr'") - _conl() - _conl("########################################################################################") - _conl() - _ini("pfx'^chrptr'sfx") - _ini("pfx'^chrptr'") - _ini("'^chrptr'sfx") - _ini("'^chrptr'") - _conl() - _conl("########################################################################################") - _conl() - } - function _tstv(p, A, r, f) - { - if (f == "") { - f = "tst_splitstr" - } - @f(_NOP, A, p) - @f(AA0, A, p) - @f(AB0, A, p) - @f(AC0, A, p) - @f("", A, p) - @f("a", A, p) - @f("\264a", A, p) - @f("\264", A, p) - @f("a\264\264\264,ba\264\264\264,", A, p) - @f("\264,", A, p) - @f(",", A, p) - @f("\264a,", A, p) - @f("ab,", A, p) - @f("ab,\264", A, p) - @f("\264a\264,,ba", A, p) - @f(",a,,b\264,c,,\264a,,\264,,,", A, p) - } - function _typ(p) - { - return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in _CLASSPTR ? "`" : (p ? 3 : 4))) : (p in _CLASSPTR ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) - } +#_______________________________________________________________________ +# _N(arr\str\mpuptr,val) \ _n(arr\str\mpuptr,val) +# This functions create new object and return ptr. +# _n() - creates object from list of deleted objects or if it's empty create new one, while _N() always create new one +# It is strongly recommended to use _N() for the objects that have some data outside of standart object arrays. Or - make routines +# that will clear outsided object data in case if object deleting. +# +# IN: arr\str\mpu,val - (both missed) just create obj and return ptr +# arr,val - create object and write arr[ptr]=val +# str,val - create object and write _[ptr][str]=val +# mpuptr - NOT ALLOWED (val missed) create object and run MPU-code specified by mpuptr with created object ptr as primary parameter +# MOD: - +# OUT: - +# RETURN: ptr - pointer to newly created object +#_________________________________________________________________ +# _tdel(ptr) +# This function exclude object from it's current structure and delete it. ptr can be later used by function: _n() for creating new object +# Also same story will occured with all chields and subchields of object specified by ptr. +# ??? What happened with linked py _ptr[ptr] objects ??? +# +# IN: ptr - pointer to object that will deleted +# MOD: - +# OUT: - +# RETURN: undefined +#_________________________________________________________________ +# _isptr(ptr) +# This function checks: is ptr is the object pointer that is currently exist? +# Unescaped remained data will be in data of src_dst_ptr. +# +# IN: ptr - string that will be tested +# MOD: - +# OUT: - +# RETURN: undefined - if ptr is not pointer to exist object +# ptr - if ptr is the pointer to exist object +#_________________________________________________________________ - function _typa(p, A) - { - return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in A ? "`" : (p ? 3 : 4))) : (p in A ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) - } - function _tzend(a, b) - { - #_____________________________________________________ - # _tframe0(hndstr,ptr) - # - # - # IN: - # MOD: - # OUT: - # RETURN: - # - # handler string: - # Handler-string divides to words. Word splitter is char ";" - # - # Note that handler-string processed left to right. This mean that next word(more rightly) will overwrite fields implemented before(leftmost). - # Note that if word-string contains more than one rexp-field then only last rexp-field(most rightly) will be applied. - #_______________________________________________ - # TO DESIGN: - # - # 0-4: complete design of tlink handler call - # 1-4: add new tlink handler call - # 1-4: add new run fn (changed rexp to different for each type: see _tframe0) - # - # hndstr: - # may be add rexp for each type of handler and also total rexp for all ??? ADDED (test) - # may be add separator char ";" ??? ADDED (test) - #_______________________________________________________________________ - ##################################################### - if (b == 0 && b == "") { - return (_TEND[_TEND[_ARRLEN]] = a) - } else { - return (_TEND[_TEND[_ARRLEN] + a] = b) - } - } - function _uidcyc(p, i) - { - _dumpuidgen(p) - for (i = 1; i < 64 * 8 * 6 - 1; i++) { - _conl(i ":" _var(_getuid(p))) - } - _dumpuidgen(p) - } +#_________________________________________________________________ +# +# TO DESIGN: +# +# create basic objectapi interface support +# modify everywhere checking ptr not by `if ( ptr )...', but by `if ( ptr in _ )...' +# _TMP0, _TMP1 name change to something like _DATA name ??? +# think about redesigning routines for not depending if ptr is exist in tsysarrs: reason: performance\light code - function _une(t) - { - return gensub(/\xB4(.)/, "\\1", "G", t) - } - function _unformatrexp(t) - { - #___________________________________________________________________________________ - _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCREXP[_FORMATSTRB[t]] : _QESCREXP[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) - } - return (_formatstrs0 _FORMATSTRA[t]) - } - function _unformatrexp_init(i, a) - { - #___________________________________________________________ - _formatstrs0 = "\\^$.[]|()*+?{}-sSwW<>yB`'" - delete _FORMATSTRB - for (i = 0; i < 256; i++) { - _QESCREXP["\\" _CHR[i]] = (index(_formatstrs0, _CHR[i]) ? "\\" _CHR[i] : _CHR[i]) - } - for (i = 0; i < 256; i++) { - a = (index(_formatstrs0, _CHR[i]) ? "\\" : "") - _QESCREXP[sprintf("%.2X", i)] = a _CHR[i] - _QESCREXP["\\" sprintf("%.3o", i)] = a _CHR[i] - if (i < 8) { - _QESCREXP["\\" sprintf("%.1o", i)] = a _CHR[i] - } - if (i < 64) { - _QESCREXP["\\" sprintf("%.2o", i)] = a _CHR[i] - } - if (i < 16) { - _QESCREXP["\\x" sprintf("%.1X", i)] = _QESCREXP["\\x" sprintf("%.1x", i)] = a _CHR[i] - } - } - patsplit("a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) - for (i in _FORMATSTRA) { - _QESCREXP["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] - } - } - function _unformatstr(t) - { - #___________________________________________________________________________________ - _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) - _formatstrs0 = "" - for (t = 1; t < _formatstrq0; t++) { - _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) - } - return (_formatstrs0 _FORMATSTRA[t]) + + + + + + + +function _tlist(L, p, f) +{ + _tlisti1 = _tlisti0 = L[_ARRLEN] + 0 + if (f == 0 && f == "") { + _tlist_i0(L, p) + } else { + _tlistf0 = (f in _TAPI ? _TAPI[f] : f) + _tlist_i1(L, p) } + return (_tlisti0 - _tlisti1) +} - function _unformatstr_init(i) - { - #___________________________________________________________ - for (i = 0; i < 256; i++) { - _QESCHR["\\" _CHR[i]] = _CHR[i] +function _tlist_i0(L, p, q, i) +{ + if (isarray(p)) { + q = p[_ARRLEN] + i = 0 + while (i++ < q) { + _tlist_i0(L, p[i]) } - for (i = 0; i < 256; i++) { - _QESCHR[sprintf("%.2X", i)] = _CHR[i] - _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i] - if (i < 8) { - _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i] - } - if (i < 64) { - _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i] - } - if (i < 16) { - _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i] - } + return + } + if (p in _) { + while (p in _tLINK) { + p = _tLINK[p] } - i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11 - patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) - for (i in _FORMATSTRA) { - _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] - } - } - - function _uninit_del(A, i, p0) - { - #_____________________________________________________________________________ - _del(i) - } - - function _unstr(t) - { - #################################################################################### - # PUBLIC: - #_____________________________________________________________________________ - # var _SYS_STDOUT - (by default = "/dev/stdout") standart output pipe filename - # var _SYS_STDERR - (by default = "/dev/stderr") standart error output pipe filename - # var _SYS_STDCON - (by default = "CON") standart console output device - #_____________________________________________________________________________ - # var _CHR["CR"] - return cursor to the position 0 without newline(normally ="\x0D") - # var _CHR["EOL"] - return cursor to the position 0 & newline (MS:="\x0D\x0A" / UX:="\x0D") - # var _CON_WIDTH - console width(columns number) - #_____________________________________________________________________________ - # fn _cmd(c) - execute shell command c and return output - # fn _err - output string w\o any addition into _SYS_STDERR device - # fn _errnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDERR device - # fn _out - output string w\o any addition into _SYS_STDOUT device - # fn _outnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDOUT device - #_____________________________________________________________________________ - # fn _con(text[,tabspace]) - # fn _conl(text[,tabspace]) - # fn _conline(text[,tabspace]) - # fn _constat(status[,tabspace]) - # fn _constatpush([status[,tabspace]]) - # fn _constatpop() - #_______________________________________________________________________ - # var _constatstr - #################################################################################### - return gensub(/\\(.)/, "\\1", "G", t) - } - - function _untmp(f, a) - { - if (f = filepath(f)) { - if (match(f, /\\$/)) { - #_________________________________________________________________ - ############################################# - _deletepfx(_FILEIO_RDTMP, a = toupper(f)) - _deletepfx(_FILEIO_RDNETMP, a) - } else { - delete _FILEIO_RDNETMP[toupper(f)] + L[++_tlisti0] = p + if (p in _tFCHLD) { + for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { + _tlist_i0(L, p) } - return f } - return "" } +} - function _val(v, t) - { - #_____________________________________________________________________________ - if (isarray(v)) { - return (_dumparr(v) _ln(t)) - } - if (v == 0 && v == "") { - return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) +function _tlist_i1(L, p) +{ + if (isarray(p)) { + q = p[_ARRLEN] + i = 0 + while (i++ < q) { + _tlist_i1(L, p[i]) } - return (_ln(v "'") _ln(t)) + return } - - function _val0(v) - { - #_____________________________________________________________________________ - if (isarray(v)) { - return _dumparr(v) - } - if (v == 0 && v == "") { - return "-" + if (p in _) { + while (p in _tLINK) { + p = _tLINK[p] } - return ("\"" v "\"") - } - - function _var(v, t) - { - #_____________________________________________________________________________ - if (isarray(v)) { - return (_dumparr(v) _ln(t)) + if (_tlistf0 in _[p]) { + L[++_tlisti0] = p } - if (v == 0 && v == "") { - return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + if (p in _tFCHLD) { + for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) { + _tlist_i1(L, p) + } + } + } +} + +#_________________________________________________________________ +function _tmbframe(f, p, p0, p1, t) +{ + ################################## + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tbframe_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) + } + return t +} + +#_________________________________________________________________ +function _tmbframex(f, p, p0, p1, t) +{ + ################################# + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tbframex_i0(f, p, p0, p1) + p = (p in _tPREV ? _tPREV[p] : "") + } + return t +} + +#_________________________________________________________________ +function _tmbpass(f, p, p0, p1) +{ + ###################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : "")) + } + return p0 +} + +#_________________________________________________________________ +function _tmbpassx(f, p, p0, p1) +{ + ##################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpassx_i0(f, p, p0, p1) + p = (p in _tPREV ? _tPREV[p] : "") + } + return p0 +} + +#_________________________________________________________________ +function _tmframe(f, p, p0, p1, p2) +{ + ################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tmframe_i0(f, p, p0, p1, p2) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tmframe_i0(f, p, p0, p1, p2, t) +{ + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframe_i0(f, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return t +} + +#___________________________________________________________ +function _tmframe_i1(F, p, p0, p1, p2, t) +{ + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframe_i1(F, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return t +} + +#_________________________________________________________________ +function _tmframex(f, p, p0, p1, t) +{ + ################################## + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + t = t _tframex_i0(f, p, p0, p1) + p = (p in _tNEXT ? _tNEXT[p] : "") + } + return t +} + +#_________________________________________________________________ +function _tmpass(f, p, p0, p1) +{ + ####################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tNEXT ? _tNEXT[p] : "")) + } + return p0 +} + +#_________________________________________________________________ +function _tmpassx(f, p, p0, p1) +{ + ###################################### + while (p && ! (_t_ENDF[0] in _t_ENDF)) { + p0 = _tbpassx_i0(f, p, p0, p1) + p = (p in _tNEXT ? _tNEXT[p] : "") + } + return p0 +} + +function _torexp(r) +{ + return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN) +} + +function _torexp_cmdstr(t) +{ + return _strtorexp(gensub(/\^(.)/, "\\1", "G", t)) +} + +function _torexp_fmask(t) +{ + return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t))) +} + +#_______________________________________________ +function _torexp_init() +{ + _TOREXPFN[""] = "_strtorexp" + _TOREXPFN["~"] = "_torexp_rexp" + _TOREXPFN["="] = "_strtorexp" + _TOREXPFN[">"] = "_torexp_cmdstr" + _TOREXPFN["#"] = "_torexp_fmask" + _TOREXPFN["\""] = "_torexp_dqstr" + _TOREXPFN["'"] = "_torexp_sqstr" +} + +#_______________________________________________ +function _torexp_rexp(t) +{ + return t +} + +#_____________________________________________________________________________ +function _tpass(f, p, p0, p1) +{ + #################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tpass_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tpass_i0(f, p, p0, p1, a) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_____________________________________________________________________________ +function _tpassx(f, p, p0, p1) +{ + ################################################### + delete _t_ENDF[++_t_ENDF[0]] + f = (p ? _tpassx_i0(f, p, p0, p1) : "") + --_t_ENDF[0] + return f +} + +#___________________________________________________________ +function _tpassx_i0(f, p, p0, p1) +{ + while (p in _tLINK) { + p = _tLINK[p] + } + return ((p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))) +} + +#_________________________________________________________________ +function _tpop(p, aA, a) +{ + ########################################### + if ((a = _tSTACK[p][0]) > 0) { + _tSTACK[p][0]-- + if (isarray(_tSTACK[p][a])) { + delete aA + _movarr(aA, _tSTACK[p][a]) + return } - return (_ln(v "'") _ln(t)) + return _tSTACK[p][a] } + _fatal("^" p ": Out of tSTACK") +} - function _verb(t, d, A) - { - if (_ERRLOG_VF) { - #_______________________________________________________________________ - ################################################## - A["TYPE"] = "VERB" - A["TEXT"] = t - _log(A, d) - } +#_____________________________________________________________________________ +function _tpush(p, aA, a) +{ + ###################################################### + if (isarray(aA)) { + delete _tSTACK[p][a = ++_tSTACK[p][0]] + _tSTACK[p][a][""] + delete _tSTACK[p][a][""] + _movarr(_tSTACK[p][a], aA) + return } - - function _wFBRO(p, v, a) - { - if (p) { - if (v) { - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - #_________________________________________________________________ - ########################################### - return v - } - } - if (p in _tPARENT) { - p = _tPARENT[p] - if (v in _tNEXT) { - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - delete _tPREV[v] - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) - } - --_tQCHLD[a] - } - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tPREV[_tFCHLD[a] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] - } - } - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } else { - if (v in _tPREV) { - if (v in _tPARENT) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - if (p == a) { - delete _tPREV[v] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) - } - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - delete _tPREV[v] - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tFCHLD[a] - delete _tLCHLD[a] - delete _tQCHLD[a] - } - } - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } - } else { - while (p in _tPREV) { - p = _tPREV[p] - } - if (v in _tPREV) { - if (v in _tPARENT) { - --_tQCHLD[a = _tPARENT[v]] - delete _tPARENT[v] - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - } else { - delete _tNEXT[_tLCHLD[a] = _tPREV[v]] - } - } else { - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - } else { - delete _tNEXT[_tPREV[v]] - } - } - delete _tPREV[v] - } else { - if (p == v) { - return v - } - if (v in _tPARENT) { - if (v in _tNEXT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tLCHLD[a = _tPARENT[v]] - delete _tFCHLD[a] - delete _tQCHLD[a] - } - delete _tPARENT[v] - } else { - if (v in _tNEXT) { - delete _tPREV[_tNEXT[v]] - } - } - } - return (_tPREV[_tNEXT[v] = p] = v) - } - } else { - ######################## p=ptr, v=0 - if (v == 0) { - return v - } - return v - } + delete _tSTACK[p][a = ++_tSTACK[p][0]] + return (_tSTACK[p][a] = aA) +} + +# prefix - +# prichr - aware character `{', `^',`]' +# sechr - aware character `.' as the first char of sechr, and character `}' +# suffix - aware character `]' +# cntptr - aware character `]' + +function _tr(n, cs, H) +{ + #_tuidinitcs[p]=cs + #2 uidel, 5 pfx, 7 hichr,11(10) lochr,14 suffix + _rconline(n ": " cs) + _rconl() + if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) { + _rconl("delptr: " _une(H[2]) "'") + _rconl("pfxstr: " _une(H[5]) "'") + _rconl("hichr: " _une(H[7]) "'") + _rconl("lochr: " _une((H[10] ? H[7] "' and " H[11] "'" : H[11] "'"))) + _rconl("sfxstr: " _une(H[14]) "'") + } else { + _rconl("NOT MATCH!") + } + _rconl() +} + +#_______________________________________________________________________ +function _trace(t, d, A) +{ + ################################################# + if (_ERRLOG_TF) { + A["TYPE"] = "TRACE" + A["TEXT"] = t + _log(A, d) + } +} + +#_________________________________________________________________ +function _trunframe(f, p, p0, p1, p2) +{ + ################################# + return _tframe((f ? f : "_trunframe_i0"), p, p0, p1, p2) +} + +#_________________________________________________________________ +function _trunframe_i0(p, p0, p1, p2, f) +{ + if (p in _tFN) { + f = _tFN[p] + return @f(p, p0, p1, p2) + } +} + +#_________________________________________________________________ +function _trunframex(f, p, p0, p1) +{ + ################################### + return _tframex((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _trunpass(f, p, p0, p1) +{ + ##################################### + return _tpass((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _trunpassx(f, p, p0, p1) +{ + #################################### + return _tpassx((f ? f : "_trunframe_i0"), p, p0, p1) +} + +#_________________________________________________________________ +function _tsetsp(p, v) +{ + ############################################# + return (_tSTACK[p][0] = v) +} + +# dptr - morg ptr; in case if object deleted then _CLASSPTR[ptr] will be deleted(object is death), but +# _tUIDEL[_CLASSPTR[ptr]] will be created that object can be resurrected from morg +# dptr can be any string containing any characters except `:'. It's not verified +# pfx,sfx - uid prefix str, and uid suffix str; this strings specifies string that can be inserted before/after +# uid generated by uid generator: +# +# class uid: pfx uidgen sfx +# +# Both can be any string(including ""), and can contains any character with B4-escaping feature. +# Note: that this strings cannot contains "'" character: it's should be escaped by B4-escaper. +# hstr,lstr - this values configure uid-generator itself. ther is a 3 combinations regarding its: +# +# hstr lstr function +# +# `ptr * - specify pointer to external uid-generator +# All uids and chars will be generated by external uid-generator +# * ^ptr - class will have it's own uid generator using external character set +# str str - class will have it's own uid generator with it's own character set +# character set inmplemented in hstr(high-charset) and in lstr(low-charset) in 2 ways: +# 1) "AB" "AB01" - this mean that high-charset contain chars: `A' and `B' +# low-charset contains chars: `A', `B', `0', `1' +# +# 2) "Az,By" "Ax,Bw,0v,1u" - this mean that high-charset contain chars: `Az' and `By' +# low-charset contains chars: `Ax', `Bw', `0v', `1u' +# Note: both: hstr and lstr cannot contain char `,' directly, but it's can uses +# B4-escaper to escape any char including `,' + + + +# !!!! in case of using `,' in hstr/lstr - the escaped `,' will leads to interpretate hstr and lstr as divided by `,' +# if parameters error then i should be more specific about what error in parameters detected +# document _inituid(): parameters; document cs: uid initialization string format +# test with escape char +# adv hstr and lstr splitting? +# chk if hstr len==0 ? +# return _tclass & report error? +# _tapi thru function + +# additional syntax checking ??? +# implement syntax and uid srv in docs +# add _dumpuid() ???? +# make performance measurement +# protection against badchar list +# additional feature to specify _getuid() to not resurrect uid; and informative that uid was ressurected or not +# build _defclass fn + +# _tuidinitcs ???? +# _tuidchrh[p] +# _tuidchrl[p] +# _tuidchr[p] +# _tuidcnt[p] +# _tUIDPFX[p] +# _tUIDSFX[p] +# _tUIDEL +# _tUIDCNTH +# _tUIDCNTL +# _tUIDCHRL +# _tUIDCHRH + +# create default class basic `new' and `del' functions + + + +function _tstini() +{ + _ini("uidel:pfx'hstr|lstr'sfx") + _ini("uidel:pfx'hstr|lstr'") + _ini("uidel:'hstr|lstr'sfx") + _ini("uidel:'hstr|lstr'") + _ini("uidel:pfx'hstr'sfx") + _ini("uidel:pfx'hstr'") + _ini("uidel:'hstr'sfx") + _ini("uidel:'hstr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'hstr|lstr'sfx") + _ini("pfx'hstr|lstr'") + _ini("'hstr|lstr'sfx") + _ini("'hstr|lstr'") + _ini("pfx'hstr'sfx") + _ini("pfx'hstr'") + _ini("'hstr'sfx") + _ini("'hstr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("uidel:pfx'`cntptr'sfx") + _ini("uidel:pfx'`cntptr'") + _ini("uidel:'`cntptr'sfx") + _ini("uidel:'`cntptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'`cntptr'sfx") + _ini("pfx'`cntptr'") + _ini("'`cntptr'sfx") + _ini("'`cntptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("uidel:pfx'^chrptr'sfx") + _ini("uidel:pfx'^chrptr'") + _ini("uidel:'^chrptr'sfx") + _ini("uidel:'^chrptr'") + _conl() + _conl("########################################################################################") + _conl() + _ini("pfx'^chrptr'sfx") + _ini("pfx'^chrptr'") + _ini("'^chrptr'sfx") + _ini("'^chrptr'") + _conl() + _conl("########################################################################################") + _conl() +} + +function _tstv(p, A, r, f) +{ + if (f == "") { + f = "tst_splitstr" + } + @f(_NOP, A, p) + @f(AA0, A, p) + @f(AB0, A, p) + @f(AC0, A, p) + @f("", A, p) + @f("a", A, p) + @f("\264a", A, p) + @f("\264", A, p) + @f("a\264\264\264,ba\264\264\264,", A, p) + @f("\264,", A, p) + @f(",", A, p) + @f("\264a,", A, p) + @f("ab,", A, p) + @f("ab,\264", A, p) + @f("\264a\264,,ba", A, p) + @f(",a,,b\264,c,,\264a,,\264,,,", A, p) +} + +function _typ(p) +{ + return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in _CLASSPTR ? "`" : (p ? 3 : 4))) : (p in _CLASSPTR ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) +} + +function _typa(p, A) +{ + return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in A ? "`" : (p ? 3 : 4))) : (p in A ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2)))))) +} + +#_____________________________________________________ +# _tframe0(hndstr,ptr) +# +# +# IN: +# MOD: +# OUT: +# RETURN: +# +# handler string: +# Handler-string divides to words. Word splitter is char ";" +# +# Note that handler-string processed left to right. This mean that next word(more rightly) will overwrite fields implemented before(leftmost). +# Note that if word-string contains more than one rexp-field then only last rexp-field(most rightly) will be applied. +#_______________________________________________ +# TO DESIGN: +# +# 0-4: complete design of tlink handler call +# 1-4: add new tlink handler call +# 1-4: add new run fn (changed rexp to different for each type: see _tframe0) +# +# hndstr: +# may be add rexp for each type of handler and also total rexp for all ??? ADDED (test) +# may be add separator char ";" ??? ADDED (test) +#_______________________________________________________________________ +function _tzend(a, b) +{ + ##################################################### + if (b == 0 && b == "") { + return (_TEND[_TEND[_ARRLEN]] = a) + } else { + return (_TEND[_TEND[_ARRLEN] + a] = b) + } +} + +function _uidcyc(p, i) +{ + _dumpuidgen(p) + for (i = 1; i < 64 * 8 * 6 - 1; i++) { + _conl(i ":" _var(_getuid(p))) + } + _dumpuidgen(p) +} + +function _une(t) +{ + return gensub(/\xB4(.)/, "\\1", "G", t) +} + +#___________________________________________________________________________________ +function _unformatrexp(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCREXP[_FORMATSTRB[t]] : _QESCREXP[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) + } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _unformatrexp_init(i, a) +{ + _formatstrs0 = "\\^$.[]|()*+?{}-sSwW<>yB`'" + delete _FORMATSTRB + for (i = 0; i < 256; i++) { + _QESCREXP["\\" _CHR[i]] = (index(_formatstrs0, _CHR[i]) ? "\\" _CHR[i] : _CHR[i]) + } + for (i = 0; i < 256; i++) { + a = (index(_formatstrs0, _CHR[i]) ? "\\" : "") + _QESCREXP[sprintf("%.2X", i)] = a _CHR[i] + _QESCREXP["\\" sprintf("%.3o", i)] = a _CHR[i] + if (i < 8) { + _QESCREXP["\\" sprintf("%.1o", i)] = a _CHR[i] + } + if (i < 64) { + _QESCREXP["\\" sprintf("%.2o", i)] = a _CHR[i] + } + if (i < 16) { + _QESCREXP["\\x" sprintf("%.1X", i)] = _QESCREXP["\\x" sprintf("%.1x", i)] = a _CHR[i] + } + } + patsplit("a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) + for (i in _FORMATSTRA) { + _QESCREXP["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] + } +} + +#___________________________________________________________________________________ +function _unformatstr(t) +{ + _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB) + _formatstrs0 = "" + for (t = 1; t < _formatstrq0; t++) { + _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])) + } + return (_formatstrs0 _FORMATSTRA[t]) +} + +#___________________________________________________________ +function _unformatstr_init(i) +{ + for (i = 0; i < 256; i++) { + _QESCHR["\\" _CHR[i]] = _CHR[i] + } + for (i = 0; i < 256; i++) { + _QESCHR[sprintf("%.2X", i)] = _CHR[i] + _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i] + if (i < 8) { + _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i] + } + if (i < 64) { + _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i] + } + if (i < 16) { + _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i] + } + } + i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11 + patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB) + for (i in _FORMATSTRA) { + _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0] + } +} + +#_____________________________________________________________________________ +function _uninit_del(A, i, p0) +{ + _del(i) +} + +#################################################################################### +# PUBLIC: +#_____________________________________________________________________________ +# var _SYS_STDOUT - (by default = "/dev/stdout") standart output pipe filename +# var _SYS_STDERR - (by default = "/dev/stderr") standart error output pipe filename +# var _SYS_STDCON - (by default = "CON") standart console output device +#_____________________________________________________________________________ +# var _CHR["CR"] - return cursor to the position 0 without newline(normally ="\x0D") +# var _CHR["EOL"] - return cursor to the position 0 & newline (MS:="\x0D\x0A" / UX:="\x0D") +# var _CON_WIDTH - console width(columns number) +#_____________________________________________________________________________ +# fn _cmd(c) - execute shell command c and return output +# fn _err - output string w\o any addition into _SYS_STDERR device +# fn _errnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDERR device +# fn _out - output string w\o any addition into _SYS_STDOUT device +# fn _outnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDOUT device +#_____________________________________________________________________________ +# fn _con(text[,tabspace]) +# fn _conl(text[,tabspace]) +# fn _conline(text[,tabspace]) +# fn _constat(status[,tabspace]) +# fn _constatpush([status[,tabspace]]) +# fn _constatpop() +#_______________________________________________________________________ +# var _constatstr +#################################################################################### + + +function _unstr(t) +{ + return gensub(/\\(.)/, "\\1", "G", t) +} + +#_________________________________________________________________ +function _untmp(f, a) +{ + ############################################# + if (f = filepath(f)) { + if (match(f, /\\$/)) { + _deletepfx(_FILEIO_RDTMP, a = toupper(f)) + _deletepfx(_FILEIO_RDNETMP, a) } else { - ######################## p=ptr, v="" - ######################## p=0 - if (p == 0) { - return v - } - ######################## p="", v=ptr - exclude v - if (v) { - return _texclude(v) - } - return v + delete _FILEIO_RDNETMP[toupper(f)] } + return f } - - function _wFCHLD(p, v, a) - { - if (p) { - if (v) { - ######################## p=v=ptr - if (p == v) { - #_________________________________________________________________ - ########################################## + return "" +} + +#_____________________________________________________________________________ +function _val(v, t) +{ + if (isarray(v)) { + return (_dumparr(v) _ln(t)) + } + if (v == 0 && v == "") { + return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + } + return (_ln(v "'") _ln(t)) +} + +#_____________________________________________________________________________ +function _val0(v) +{ + if (isarray(v)) { + return _dumparr(v) + } + if (v == 0 && v == "") { + return "-" + } + return ("\"" v "\"") +} + +#_____________________________________________________________________________ +function _var(v, t) +{ + if (isarray(v)) { + return (_dumparr(v) _ln(t)) + } + if (v == 0 && v == "") { + return (_ln("- (ERRNO=" ERRNO ")") _ln(t)) + } + return (_ln(v "'") _ln(t)) +} + +#_______________________________________________________________________ +function _verb(t, d, A) +{ + ################################################## + if (_ERRLOG_VF) { + A["TYPE"] = "VERB" + A["TEXT"] = t + _log(A, d) + } +} + +#_________________________________________________________________ +function _wFBRO(p, v, a) +{ + ########################################### + if (p) { + if (v) { + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } + } + ######################## v is parentesis of p + if (p in _tPARENT) { + p = _tPARENT[p] if (v in _tNEXT) { if (v in _tPREV) { _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] @@ -7263,11 +7271,8 @@ delete _tPREV[_tNEXT[v]] } } - if (p in _tFCHLD) { - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } - delete _tNEXT[v] + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } else { if (v in _tPREV) { if (v in _tPARENT) { @@ -7291,181 +7296,184 @@ delete _tQCHLD[a] } } - if (p in _tFCHLD) { - ++_tQCHLD[p] - return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) - } + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } - _tQCHLD[p] = 1 - return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v) } else { - if (v == 0) { - if (p in _tFCHLD) { - ######################## p=ptr, v=0 > delete all chld - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + while (p in _tPREV) { + p = _tPREV[p] + } + if (v in _tPREV) { + if (v in _tPARENT) { + --_tQCHLD[a = _tPARENT[v]] + delete _tPARENT[v] + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + } else { + delete _tNEXT[_tLCHLD[a] = _tPREV[v]] + } + } else { + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + } else { + delete _tNEXT[_tPREV[v]] + } + } + delete _tPREV[v] + } else { + if (p == v) { + return v + } + if (v in _tPARENT) { + if (v in _tNEXT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + --_tQCHLD[a] + } else { + delete _tLCHLD[a = _tPARENT[v]] + delete _tFCHLD[a] + delete _tQCHLD[a] + } + delete _tPARENT[v] + } else { + if (v in _tNEXT) { + delete _tPREV[_tNEXT[v]] + } } } - return v + return (_tPREV[_tNEXT[v] = p] = v) } } else { - ######################## p=ptr, v="" > ignore action - ######################## p=0 - if (p == 0) { + if (v == 0) { return v } + ######################## p=ptr, v=0 + return v + } + } else { + ######################## p=ptr, v="" + if (p == 0) { return v } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v + return v } +} - function _wLBRO(p, v, a) - { - if (p) { - if (v) { - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - #_________________________________________________________________ - ########################################### - return v - } +#_________________________________________________________________ +function _wFCHLD(p, v, a) +{ + ########################################## + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { + return v } - if (p in _tPARENT) { - p = _tPARENT[p] - if (v in _tPREV) { - if (v in _tNEXT) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] - delete _tNEXT[v] - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) - } - --_tQCHLD[a] - } - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tNEXT[_tLCHLD[a] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - } - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } else { - if (v in _tNEXT) { - if (v in _tPARENT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - if (p == a) { - delete _tNEXT[v] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) - } - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] - } - delete _tNEXT[v] - } else { - if (v in _tPARENT) { - if (p == (a = _tPARENT[v])) { - return v - } - delete _tLCHLD[a] - delete _tFCHLD[a] - delete _tQCHLD[a] - } + } + ######################## v is parentesis of p + if (v in _tNEXT) { + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + delete _tPREV[v] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) } - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) + --_tQCHLD[a] } } else { - while (p in _tNEXT) { - p = _tNEXT[p] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v + } + delete _tPREV[_tFCHLD[a] = _tNEXT[v]] + --_tQCHLD[a] + } else { + delete _tPREV[_tNEXT[v]] } - if (v in _tNEXT) { - if (v in _tPARENT) { - --_tQCHLD[a = _tPARENT[v]] - delete _tPARENT[v] - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - } else { - delete _tPREV[_tFCHLD[a] = _tNEXT[v]] - } - } else { - if (v in _tPREV) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] - } else { - delete _tPREV[_tNEXT[v]] - } + } + if (p in _tFCHLD) { + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) + } + delete _tNEXT[v] + } else { + if (v in _tPREV) { + if (v in _tPARENT) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + if (p == a) { + delete _tPREV[v] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v) } - delete _tNEXT[v] + --_tQCHLD[a] } else { - if (p == v) { + delete _tNEXT[_tPREV[v]] + } + delete _tPREV[v] + } else { + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { return v } - if (v in _tPARENT) { - if (v in _tPREV) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tFCHLD[a = _tPARENT[v]] - delete _tLCHLD[a] - delete _tQCHLD[a] - } - delete _tPARENT[v] - } else { - if (v in _tPREV) { - delete _tNEXT[_tPREV[v]] - } - } + delete _tFCHLD[a] + delete _tLCHLD[a] + delete _tQCHLD[a] } - return (_tNEXT[_tPREV[v] = p] = v) } - } else { - ######################## p=ptr, v=0 - if (v == 0) { - return v + if (p in _tFCHLD) { + ++_tQCHLD[p] + return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v) } - return v } + _tQCHLD[p] = 1 + return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v) } else { - ######################## p=ptr, v="" - ######################## p=0 - if (p == 0) { - return v - } - ######################## p="", v=ptr - exclude v - if (v) { - return _texclude(v) + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } } return v } + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v + } + ######################## p=0 + return v } +} - function _wLCHLD(p, v, a) - { - if (p) { - if (v) { - ######################## p=v=ptr - if (p == v) { - #_________________________________________________________________ - ########################################## +#_________________________________________________________________ +function _wLBRO(p, v, a) +{ + ########################################### + if (p) { + if (v) { + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } + } + ######################## v is parentesis of p + if (p in _tPARENT) { + p = _tPARENT[p] if (v in _tPREV) { if (v in _tNEXT) { _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] @@ -7487,11 +7495,8 @@ delete _tNEXT[_tPREV[v]] } } - if (p in _tLCHLD) { - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } - delete _tPREV[v] + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } else { if (v in _tNEXT) { if (v in _tPARENT) { @@ -7515,664 +7520,802 @@ delete _tQCHLD[a] } } - if (p in _tLCHLD) { - ++_tQCHLD[p] - return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) - } + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } - _tQCHLD[p] = 1 - return (_tLCHLD[_tPARENT[v] = p] = _tFCHLD[p] = v) } else { - if (v == 0) { - if (p in _tFCHLD) { - ######################## p=ptr, v=0 > delete all chld - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + while (p in _tNEXT) { + p = _tNEXT[p] + } + if (v in _tNEXT) { + if (v in _tPARENT) { + --_tQCHLD[a = _tPARENT[v]] + delete _tPARENT[v] + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + } else { + delete _tPREV[_tFCHLD[a] = _tNEXT[v]] + } + } else { + if (v in _tPREV) { + _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v] + } else { + delete _tPREV[_tNEXT[v]] + } + } + delete _tNEXT[v] + } else { + if (p == v) { + return v + } + if (v in _tPARENT) { + if (v in _tPREV) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + --_tQCHLD[a] + } else { + delete _tFCHLD[a = _tPARENT[v]] + delete _tLCHLD[a] + delete _tQCHLD[a] + } + delete _tPARENT[v] + } else { + if (v in _tPREV) { + delete _tNEXT[_tPREV[v]] + } } } - return v + return (_tNEXT[_tPREV[v] = p] = v) } } else { - ######################## p=ptr, v="" > ignore action - ######################## p=0 - if (p == 0) { + if (v == 0) { return v } + ######################## p=ptr, v=0 return v } + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v + } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v + return v } +} - function _wLINK(p, v) - { - #_________________________________________________________________ - ############################################## - return (_tLINK[p] = v) - } - - function _wNEXT(p, v, a, b) - { - if (p) { - if (v) { - ######################## p=v=ptr - if (p == v) { - #_________________________________________________________________ - ######################################### +#_________________________________________________________________ +function _wLCHLD(p, v, a) +{ + ########################################## + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } - } - if (v in _tPREV) { - if (p == (a = _tPREV[v])) { - return v - } - if (v in _tNEXT) { - _tPREV[_tNEXT[a] = _tNEXT[v]] = a - if (v in _tPARENT) { - --_tQCHLD[_tPARENT[v]] - } - } else { - delete _tNEXT[a] - if (v in _tPARENT) { - _tLCHLD[b = _tPARENT[v]] = a - --_tQCHLD[b] + } + ######################## v is parentesis of p + if (v in _tPREV) { + if (v in _tNEXT) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v] + delete _tNEXT[v] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) } + --_tQCHLD[a] } } else { - if (v in _tNEXT) { - if (v in _tPARENT) { - delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] - --_tQCHLD[a] - } else { - delete _tPREV[_tNEXT[v]] + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v } + delete _tNEXT[_tLCHLD[a] = _tPREV[v]] + --_tQCHLD[a] } else { - if (v in _tPARENT) { - delete _tFCHLD[a = _tPARENT[v]] - delete _tLCHLD[a] - delete _tQCHLD[a] - } + delete _tNEXT[_tPREV[v]] } } - if (p in _tNEXT) { - _tPREV[_tNEXT[v] = _tNEXT[p]] = v - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + if (p in _tLCHLD) { + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) + } + delete _tPREV[v] + } else { + if (v in _tNEXT) { + if (v in _tPARENT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + if (p == a) { + delete _tNEXT[v] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v) + } + --_tQCHLD[a] } else { - delete _tPARENT[v] + delete _tPREV[_tNEXT[v]] } - } else { delete _tNEXT[v] - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]] - } else { - delete _tPARENT[v] + } else { + if (v in _tPARENT) { + if (p == (a = _tPARENT[v])) { + return v + } + delete _tLCHLD[a] + delete _tFCHLD[a] + delete _tQCHLD[a] } } - return (_tNEXT[_tPREV[v] = p] = v) - } else { - ######################## p=ptr, v=0 - if (v == 0) { - return v + if (p in _tLCHLD) { + ++_tQCHLD[p] + return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v) } - return v } + _tQCHLD[p] = 1 + return (_tLCHLD[_tPARENT[v] = p] = _tFCHLD[p] = v) } else { - ######################## p=ptr, v="" - ######################## p=0 - if (p == 0) { - return v - } - ######################## p="", v=ptr - exclude v - if (v) { - return _texclude(v) + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } } return v } - } - - function _wPARENT(p, v) - { - #_________________________________________________________________ - ############################################ + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v + } + ######################## p=0 return v } - - function _wPREV(p, v, a, b) - { - if (p) { - if (v) { - ######################## p=v=ptr - if (p == v) { - #_________________________________________________________________ - ######################################### +} + +#_________________________________________________________________ +function _wLINK(p, v) +{ + ############################################## + return (_tLINK[p] = v) +} + +#_________________________________________________________________ +function _wNEXT(p, v, a, b) +{ + ######################################### + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { return v } - ######################## v is parentesis of p - for (a = p; a in _tPARENT; ) { - if ((a = _tPARENT[a]) == v) { - return v - } + } + ######################## v is parentesis of p + if (v in _tPREV) { + if (p == (a = _tPREV[v])) { + return v } if (v in _tNEXT) { - if (p == (a = _tNEXT[v])) { - return v - } - if (v in _tPREV) { - _tNEXT[_tPREV[a] = _tPREV[v]] = a - if (v in _tPARENT) { - --_tQCHLD[_tPARENT[v]] - } - } else { - delete _tPREV[a] - if (v in _tPARENT) { - _tFCHLD[b = _tPARENT[v]] = a - --_tQCHLD[b] - } + _tPREV[_tNEXT[a] = _tNEXT[v]] = a + if (v in _tPARENT) { + --_tQCHLD[_tPARENT[v]] } } else { - if (v in _tPREV) { - if (v in _tPARENT) { - delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] - --_tQCHLD[a] - } else { - delete _tNEXT[_tPREV[v]] - } - } else { - if (v in _tPARENT) { - delete _tLCHLD[a = _tPARENT[v]] - delete _tFCHLD[a] - delete _tQCHLD[a] - } + delete _tNEXT[a] + if (v in _tPARENT) { + _tLCHLD[b = _tPARENT[v]] = a + --_tQCHLD[b] } } - if (p in _tPREV) { - _tNEXT[_tPREV[v] = _tPREV[p]] = v - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + if (v in _tNEXT) { + if (v in _tPARENT) { + delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]] + --_tQCHLD[a] } else { - delete _tPARENT[v] + delete _tPREV[_tNEXT[v]] } } else { - delete _tPREV[v] - if (p in _tPARENT) { - ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]] - } else { - delete _tPARENT[v] + if (v in _tPARENT) { + delete _tFCHLD[a = _tPARENT[v]] + delete _tLCHLD[a] + delete _tQCHLD[a] } } - return (_tPREV[_tNEXT[v] = p] = v) + } + if (p in _tNEXT) { + _tPREV[_tNEXT[v] = _tNEXT[p]] = v + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + delete _tPARENT[v] + } } else { - ######################## p=ptr, v=0 - if (v == 0) { - return v + delete _tNEXT[v] + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]] + } else { + delete _tPARENT[v] } - return v } + return (_tNEXT[_tPREV[v] = p] = v) } else { - ######################## p=ptr, v="" - ######################## p=0 - if (p == 0) { + if (v == 0) { return v } - ######################## p="", v=ptr - exclude v - if (v) { - return _texclude(v) - } + ######################## p=ptr, v=0 return v } - } - - function _wQBRO(p, v) - { - #_________________________________________________________________ - ############################################## + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v + } + ######################## p=0 + if (v) { + return _texclude(v) + } + ######################## p="", v=ptr - exclude v return v } - - function _wQCHLD(p, v) - { - if (p) { - if (v) { +} + +#_________________________________________________________________ +function _wPARENT(p, v) +{ + ############################################ + return v +} + +#_________________________________________________________________ +function _wPREV(p, v, a, b) +{ + ######################################### + if (p) { + if (v) { + if (p == v) { + return v + } + ######################## p=v=ptr + for (a = p; a in _tPARENT; ) { + if ((a = _tPARENT[a]) == v) { + return v + } + } + ######################## v is parentesis of p + if (v in _tNEXT) { + if (p == (a = _tNEXT[v])) { + return v + } + if (v in _tPREV) { + _tNEXT[_tPREV[a] = _tPREV[v]] = a + if (v in _tPARENT) { + --_tQCHLD[_tPARENT[v]] + } + } else { + delete _tPREV[a] + if (v in _tPARENT) { + _tFCHLD[b = _tPARENT[v]] = a + --_tQCHLD[b] + } + } } else { - if (v == 0) { - if (p in _tFCHLD) { - #_________________________________________________________________ - ############################################# - ######################## p=ptr, v=ptr - ######################## p=ptr, v=0 > delete all chld - v = _tFCHLD[p] - delete _tFCHLD[p] - delete _tLCHLD[p] - delete _tQCHLD[p] - do { - delete _tPARENT[v] - } while (v in _tNEXT && (v = _tNEXT[v])) + if (v in _tPREV) { + if (v in _tPARENT) { + delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]] + --_tQCHLD[a] + } else { + delete _tNEXT[_tPREV[v]] + } + } else { + if (v in _tPARENT) { + delete _tLCHLD[a = _tPARENT[v]] + delete _tFCHLD[a] + delete _tQCHLD[a] } } - return v } + if (p in _tPREV) { + _tNEXT[_tPREV[v] = _tPREV[p]] = v + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[v] = _tPARENT[p]] + } else { + delete _tPARENT[v] + } + } else { + delete _tPREV[v] + if (p in _tPARENT) { + ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]] + } else { + delete _tPARENT[v] + } + } + return (_tPREV[_tNEXT[v] = p] = v) } else { - ######################## p=0 - if (p == 0) { - ######################## p=ptr, v="" > ignore action + if (v == 0) { return v } + ######################## p=ptr, v=0 return v } - } - - function _warning(t, d, A) - { - if (_ERRLOG_WF) { - #_______________________________________________________________________ - ############################################### - A["TYPE"] = "WARNING" - A["TEXT"] = t - _log(A, d) + } else { + ######################## p=ptr, v="" + if (p == 0) { + return v + } + ######################## p=0 + if (v) { + return _texclude(v) } + ######################## p="", v=ptr - exclude v + return v } - - function _wfilerdnehnd(f, t) - { - #___________________________________________________________ - if ((f = _filerdne(f)) == "") { - return "" +} + +#_________________________________________________________________ +function _wQBRO(p, v) +{ + ############################################## + return v +} + +#_________________________________________________________________ +function _wQCHLD(p, v) +{ + ############################################# + if (p) { + if (v) { + } else { + ######################## p=ptr, v=ptr + if (v == 0) { + if (p in _tFCHLD) { + ######################## p=ptr, v=0 > delete all chld + v = _tFCHLD[p] + delete _tFCHLD[p] + delete _tLCHLD[p] + delete _tQCHLD[p] + do { + delete _tPARENT[v] + } while (v in _tNEXT && (v = _tNEXT[v])) + } + } + return v } - if (! ((t = _filerd(f)) in _WFILEROOTDIR)) { - _cmd("md \"" t "\" 2>NUL") - _WFILEROOTDIR[t] + } else { + ######################## p=ptr, v="" > ignore action + if (p == 0) { + return v } - return f + ######################## p=0 + return v } +} - function _wonl(t) - { - wonl = wonl _ln(t) +#_______________________________________________________________________ +function _warning(t, d, A) +{ + ############################################### + if (_ERRLOG_WF) { + A["TYPE"] = "WARNING" + A["TEXT"] = t + _log(A, d) } +} - function _wonline(t) - { - wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126)) +#___________________________________________________________ +function _wfilerdnehnd(f, t) +{ + if ((f = _filerdne(f)) == "") { + return "" } - - function _wr_shortcut(f, S) - { - if (_shrtcutf0 = _filepath(f)) { - #___________________________________________________________ - ERRNO = "" - _shrtcuta0 = _shortcut_fpath " /A:C /F:\"" _shrtcutf0 "\" 2>&1" - for (f in _SHORTCUTWSTRUC) { - if (f in S) { - _shrtcuta0 = _shrtcuta0 " " _SHORTCUTWSTRUC[f] "\"" (gensub(/(\\?)$/, "\\1\\1", 1, S[f])) "\"" - } - } - if (_shortcut_nerr(_cmd(_shrtcuta0), _shrtcutf0)) { - return - } - } - return ((ERRNO ? ERRNO = "write shortcut: " ERRNO : _NOP)) + if (! ((t = _filerd(f)) in _WFILEROOTDIR)) { + _cmd("md \"" t "\" 2>NUL") + _WFILEROOTDIR[t] } + return f +} - function _wrfile(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - #_________________________________________________________________ - ######################################### - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" - ERRNO = "" - print(d) > f - if (ERRNO) { - return "" - } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" - } - return f - } +function _wonl(t) +{ + wonl = wonl _ln(t) +} - function _wrfile1(f, d, a, b) - { - if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { - #___________________________________________________________ - ################################## - ERRNO = "Filename error" - return - } - a = BINMODE - BINMODE = "rw" - b = ORS - ORS = "" +function _wonline(t) +{ + wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126)) +} + +#___________________________________________________________ +function _wr_shortcut(f, S) +{ + if (_shrtcutf0 = _filepath(f)) { ERRNO = "" - print(d) > f - if (ERRNO) { - return "" + _shrtcuta0 = _shortcut_fpath " /A:C /F:\"" _shrtcutf0 "\" 2>&1" + for (f in _SHORTCUTWSTRUC) { + if (f in S) { + _shrtcuta0 = _shrtcuta0 " " _SHORTCUTWSTRUC[f] "\"" (gensub(/(\\?)$/, "\\1\\1", 1, S[f])) "\"" + } } - close(f) - BINMODE = a - ORS = b - if (ERRNO) { - return "" + if (_shortcut_nerr(_cmd(_shrtcuta0), _shrtcutf0)) { + return } - return d } + return ((ERRNO ? ERRNO = "write shortcut: " ERRNO : _NOP)) +} - function _yexport(p) - { - #_______________________________________________________________________ - ##################################################### - return _tframe("_yexport_i0", p) +#_________________________________________________________________ +function _wrfile(f, d, a, b) +{ + ######################################### + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function _yexport_i0(p, p0, p1, p2) - { - #_______________________________________________________________________ - if (p in _tLOG) { - return ("_ERRLOG: " _Zexparr(_tLOG[p]) "\n") - } - if (p in _tSTR) { - p = _tSTR[p] - gsub(/\x1B/, "\033;", p) - gsub(/\x0A/, "\033:", p) - return (p "\n") - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) > f + if (ERRNO) { + return "" } - - function cmp_str_idx(i1, v1, i2, v2) - { - #_________________________________________________________________ - ############################## - return ((i1 < i2 ? -1 : 1)) + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" } + return f +} - function filedi(f, d) - { - #___________________________________________________________ - if ((f = filerdnehndi(f)) == "") { - return _FILEIO_D - } - if (f in _FILEDIRFL) { - return _FILEDIR[f] - } - if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] - } - return (_FILEDIR[f] = d _FILEDIR[f]) - } - if ((_FILEIO_RD, f) in _FILEDIR) { - return _FILEDIR[_FILEIO_RD, f] - } - return (_FILEDIR[_FILEIO_RD, f] = _FILEIO_D _FILEDIR[f]) +#___________________________________________________________ +function _wrfile1(f, d, a, b) +{ + ################################## + if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") { + ERRNO = "Filename error" + return } - - function filegetdrvdir(t, r) - { - #___________________________________________________________ - if (t in _FILEDRV) { - return _FILEDRV[t] - } - if (match(r = _cmd("cd " t " 2>NUL"), /[^\x00-\x1F]+/)) { - r = gensub(/[ \t]*([\\\$\:])[ \t]*/, "\\1", "G", substr(r, RSTART, RLENGTH)) - gsub(/(^[ \t]*)|([ \t]*$)/, "", r) - if (match(r, /\:(.*)/)) { - return (_FILEDRV[tolower(t)] = _FILEDRV[toupper(t)] = substr(r, RSTART + 1) ((r ~ /\\$/ ? "" : "\\"))) - } - } + a = BINMODE + BINMODE = "rw" + b = ORS + ORS = "" + ERRNO = "" + print(d) > f + if (ERRNO) { return "" } - - function filegetrootdir(f, dd, d) - { - if (f in _FILEDIRFL) { - #___________________________________________________________ - if (f in _FILEROOT) { - return (_FILEROOT[f] _FILEDIR[f]) - } - if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - return (_FILEROOT[dd, f] _FILEDIR[f]) - } - return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[f]) - } + close(f) + BINMODE = a + ORS = b + if (ERRNO) { + return "" + } + return d +} + +#_______________________________________________________________________ +function _yexport(p) +{ + ##################################################### + return _tframe("_yexport_i0", p) +} + +#_______________________________________________________________________ +function _yexport_i0(p, p0, p1, p2) +{ + if (p in _tLOG) { + return ("_ERRLOG: " _Zexparr(_tLOG[p]) "\n") + } + if (p in _tSTR) { + p = _tSTR[p] + gsub(/\x1B/, "\033;", p) + gsub(/\x0A/, "\033:", p) + return (p "\n") + } +} + +#_________________________________________________________________ +function cmp_str_idx(i1, v1, i2, v2) +{ + ############################## + return ((i1 < i2 ? -1 : 1)) +} + +#___________________________________________________________ +function filedi(f, d) +{ + if ((f = filerdnehndi(f)) == "") { + return _FILEIO_D + } + if (f in _FILEDIRFL) { + return _FILEDIR[f] + } + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] + } + return (_FILEDIR[f] = d _FILEDIR[f]) + } + if ((_FILEIO_RD, f) in _FILEDIR) { + return _FILEDIR[_FILEIO_RD, f] + } + return (_FILEDIR[_FILEIO_RD, f] = _FILEIO_D _FILEDIR[f]) +} + +#___________________________________________________________ +function filegetdrvdir(t, r) +{ + if (t in _FILEDRV) { + return _FILEDRV[t] + } + if (match(r = _cmd("cd " t " 2>NUL"), /[^\x00-\x1F]+/)) { + r = gensub(/[ \t]*([\\\$\:])[ \t]*/, "\\1", "G", substr(r, RSTART, RLENGTH)) + gsub(/(^[ \t]*)|([ \t]*$)/, "", r) + if (match(r, /\:(.*)/)) { + return (_FILEDRV[tolower(t)] = _FILEDRV[toupper(t)] = substr(r, RSTART + 1) ((r ~ /\\$/ ? "" : "\\"))) + } + } + return "" +} + +#___________________________________________________________ +function filegetrootdir(f, dd, d) +{ + if (f in _FILEDIRFL) { if (f in _FILEROOT) { - if (d = filegetdrvdir(_FILEROOT[f])) { - _FILEDIRFL[f] - return (_FILEROOT[f] (_FILEDIR[f] = d _FILEDIR[f])) - } else { - return (_FILEROOT[f] _FILEDIR[f]) - } + return (_FILEROOT[f] _FILEDIR[f]) } if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { - if ((dd, f) in _FILEDIR) { - return (_FILEROOT[dd, f] _FILEDIR[dd, f]) - } - if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return (_FILEROOT[dd, f] (_FILEDIR[dd, f] = d)) - } - return (_FILEROOT[dd, f] d) + return (_FILEROOT[dd, f] _FILEDIR[f]) } + return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[f]) + } + if (f in _FILEROOT) { + if (d = filegetdrvdir(_FILEROOT[f])) { + _FILEDIRFL[f] + return (_FILEROOT[f] (_FILEDIR[f] = d _FILEDIR[f])) + } else { + return (_FILEROOT[f] _FILEDIR[f]) + } + } + if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEROOT) { if ((dd, f) in _FILEDIR) { - return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f]) + return (_FILEROOT[dd, f] _FILEDIR[dd, f]) } if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { - return ((_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d)) + return (_FILEROOT[dd, f] (_FILEDIR[dd, f] = d)) } - return ((_FILEROOT[dd, f] = fileri(dd)) d) + return (_FILEROOT[dd, f] d) } + if ((dd, f) in _FILEDIR) { + return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f]) + } + if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) { + return ((_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d)) + } + return ((_FILEROOT[dd, f] = fileri(dd)) d) +} - function filerdnehndi(st, a, c, r, d, n, A) - { - if (st) { - #___________________________________________________________ - if ((c = toupper(st)) in _FILECACHE) { - return _FILECACHE[c] - } - if (match(st, /^[ \t]*\\[ \t]*\\/)) { - if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { - a = a + RLENGTH - d = ((A[3] ? "\\" A[3] "$" : "")) "\\" A[5] - gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d - _FILEDIRFL[c] - _FILEROOT[c] = r - } else { - _filepath_err = "UNC" - return "" - } - } else { - match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) - if (! RLENGTH) { - return "" - } - d = A[8] A[10] +#___________________________________________________________ +function filerdnehndi(st, a, c, r, d, n, A) +{ + if (st) { + if ((c = toupper(st)) in _FILECACHE) { + return _FILECACHE[c] + } + if (match(st, /^[ \t]*\\[ \t]*\\/)) { + if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) { + a = a + RLENGTH + d = ((A[3] ? "\\" A[3] "$" : "")) "\\" A[5] gsub(/[ \t]*\\[ \t]*/, "\\", d) - if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { - return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st]) - } - _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d - if (A[8]) { - _FILEDIRFL[c] - } - if (r) { - _FILEROOT[c] = r + if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st]) } + _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d + _FILEDIRFL[c] + _FILEROOT[c] = r + } else { + _filepath_err = "UNC" + return "" } - if (n) { - if (match(n, /\.[^\.]*$/)) { - _FILEXT[c] = substr(n, RSTART) - _FILENAM[c] = substr(n, 1, RSTART - 1) - } else { - _FILENAM[c] = n - } + } else { + match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A) + if (! RLENGTH) { + return "" + } + d = A[8] A[10] + gsub(/[ \t]*\\[ \t]*/, "\\", d) + if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) { + return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st]) + } + _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d + if (A[8]) { + _FILEDIRFL[c] + } + if (r) { + _FILEROOT[c] = r } - return c - } - return "" - } - - function fileri(f) - { - #_____________________________________________________ - if ((f = filerdnehndi(f)) == "") { - return _FILEIO_R - } - if (f in _FILEROOT) { - return _FILEROOT[f] - } - if ((_FILEIO_RD, f) in _FILEROOT) { - return _FILEROOT[_FILEIO_RD, f] } - return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R) - } - - function hujf(a, b, c) - { - _conl("hujf(" a "," b "," c ")") - } - - function ncmp_str_idx(i1, v1, i2, v2) - { - #___________________________________________________________ - ####################### - return ((i1 < i2 ? 1 : -1)) - } - - function test_cfg(p, z, AA0, a) - { - AA0[1] - _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys) - _conl() - _conline() - _conl() - _drawuid(p) - _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys) - _conl() - _conline() - _conl() - _drawuid(p) - a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd")) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z)) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys)) - _conl("### " a "########") - _conline() - _conl() - _drawuid(p) - _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd") - _conl() - _conline() - _conl() - _drawuid(p) - _conl("```````````````````" z "'''''''''" ((_isptr(z) ? " ptr" : " not ptr"))) - _drawuid(z) - } - - function test_splitstr(A) - { - AA0[-1] = "huj" - AA0["A"] = "pizda" - AA0[1] = "zhopa" - delete AB0[AB0[""] = ""] - AC0[-1] = "HUJ" - AC0["A"] = "PIZDA" - AC0[1] = "ZHOPA" - _SPLITSTRB0["1"] - wonl = "" - _tstv(0, A, 0, "_tstv") - _conl(wonl) - _wrfile("wonl.out", wonl) - } - - function test_uid(p, i) - { - #test_cfg() - #return - #_fclass=_cfguid(p=_getuid(_classys),_NOP,_NOP,_NOP,"",_classys) - _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc") - _conl("_fclass uid: " _getuid(_fclass)) - _drawuid(_fclass) - _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys) - for (i = 1; i < 81; i++) { - _conl(i ": " _getuid(_fclass)) - } - _drawuid(_fclass) - } - - function tst_splitstr(t, A, R, r) - { - delete A - A["not cleared"] - _wonl() - _wonline("_splitstr(" ((isarray(t) ? "ARR" ((length(t) > 0 ? "#" ((t[1] != "zhopa" ? "U" : "l")) : "")) : _val0(t))) ",A" ((isarray(R) ? ", ARR" ((length(R) > 0 ? "#" ((R[1] != "zhopa" ? "U" : "l")) : "")) : ", " _val0(R))) "):") - _wonl(_val0(r = _splitstr(t, A, R))) - _wonl("arrary A:") - _wonl(_dumparr(A)) - return r - } - - function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im) - { - im = " " - im = ".. .." - _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'") - _conl("mask: `" _qparamask "'") - } - - function zorr(A, i, r) - { - # # - p is array - # ` - p is ptr detected in array _CLASSPTR(for _typ); or p is ptr detected in array A(for _typa) - # 0 - p is undefined - # 2 - p is string=="" - # 3 - p is string!="" - # 4 - p is number 0 - # 5 - p is any number except 0(positive and negative) - # str: _typ(p)+0 !_typ(p)+0 - # str/ptr _typ(p)>0 _typ(p)<1 - # str/arr "`">_typ(p0) && _t0 - # str/ptr/arr _typ(p) !_typ(p) - # ptr _typ(p)=="`" _typ(p)<"`" ? - # ptr/arr _typ(p)+0!=_t0 - # arr _typ(p)=="#" _typ(p)>"#" ? - if (i in A) { - _conl("`" i "' in A") - } else { - _conl("`" i "' not in A") + if (n) { + if (match(n, /\.[^\.]*$/)) { + _FILEXT[c] = substr(n, RSTART) + _FILENAM[c] = substr(n, 1, RSTART - 1) + } else { + _FILENAM[c] = n + } } - r = A[i] == "" && A[i] == 0 - _conl("A[" i "] status is " r) - return - a = a + -a - _conl("``````````````" a "''''''''''''''''") - } - - function zzer() - { + return c } + return "" +} + +#_____________________________________________________ +function fileri(f) +{ + if ((f = filerdnehndi(f)) == "") { + return _FILEIO_R + } + if (f in _FILEROOT) { + return _FILEROOT[f] + } + if ((_FILEIO_RD, f) in _FILEROOT) { + return _FILEROOT[_FILEIO_RD, f] + } + return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R) +} + +function hujf(a, b, c) +{ + _conl("hujf(" a "," b "," c ")") +} + +#___________________________________________________________ +function ncmp_str_idx(i1, v1, i2, v2) +{ + ####################### + return ((i1 < i2 ? 1 : -1)) +} + +function test_cfg(p, z, AA0, a) +{ + AA0[1] + _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys) + _conl() + _conline() + _conl() + _drawuid(p) + _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys) + _conl() + _conline() + _conl() + _drawuid(p) + a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd")) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z)) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys)) + _conl("### " a "########") + _conline() + _conl() + _drawuid(p) + _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd") + _conl() + _conline() + _conl() + _drawuid(p) + _conl("```````````````````" z "'''''''''" ((_isptr(z) ? " ptr" : " not ptr"))) + _drawuid(z) +} + +function test_splitstr(A) +{ + AA0[-1] = "huj" + AA0["A"] = "pizda" + AA0[1] = "zhopa" + delete AB0[AB0[""] = ""] + AC0[-1] = "HUJ" + AC0["A"] = "PIZDA" + AC0[1] = "ZHOPA" + _SPLITSTRB0["1"] + wonl = "" + _tstv(0, A, 0, "_tstv") + _conl(wonl) + _wrfile("wonl.out", wonl) +} + +function test_uid(p, i) +{ + #test_cfg() + #return + + _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc") + #_fclass=_cfguid(p=_getuid(_classys),_NOP,_NOP,_NOP,"",_classys) + _conl("_fclass uid: " _getuid(_fclass)) + _drawuid(_fclass) + _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys) + for (i = 1; i < 81; i++) { + _conl(i ": " _getuid(_fclass)) + } + _drawuid(_fclass) +} + +function tst_splitstr(t, A, R, r) +{ + delete A + A["not cleared"] + _wonl() + _wonline("_splitstr(" ((isarray(t) ? "ARR" ((length(t) > 0 ? "#" ((t[1] != "zhopa" ? "U" : "l")) : "")) : _val0(t))) ",A" ((isarray(R) ? ", ARR" ((length(R) > 0 ? "#" ((R[1] != "zhopa" ? "U" : "l")) : "")) : ", " _val0(R))) "):") + _wonl(_val0(r = _splitstr(t, A, R))) + _wonl("arrary A:") + _wonl(_dumparr(A)) + return r +} + +function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im) +{ + im = " " + im = ".. .." + _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'") + _conl("mask: `" _qparamask "'") +} + +# # - p is array +# ` - p is ptr detected in array _CLASSPTR(for _typ); or p is ptr detected in array A(for _typa) +# 0 - p is undefined + +# 2 - p is string=="" +# 3 - p is string!="" +# 4 - p is number 0 +# 5 - p is any number except 0(positive and negative) + +# str: _typ(p)+0 !_typ(p)+0 +# str/ptr _typ(p)>0 _typ(p)<1 +# str/arr "`">_typ(p0) && _t0 +# str/ptr/arr _typ(p) !_typ(p) +# ptr _typ(p)=="`" _typ(p)<"`" ? +# ptr/arr _typ(p)+0!=_t0 +# arr _typ(p)=="#" _typ(p)>"#" ? + +function zorr(A, i, r) +{ + if (i in A) { + _conl("`" i "' in A") + } else { + _conl("`" i "' not in A") + } + r = A[i] == "" && A[i] == 0 + _conl("A[" i "] status is " r) + return + a = a + -a + _conl("``````````````" a "''''''''''''''''") +} + +#_____________________________________________________________________________ +function zzer() +{ + ################################################################ +} |